Java 关于数据库 Entity 如何设计

2022-07-28 09:50:43 +08:00
 hahaFck

喜欢写 sql ,所以不想用 hibernate 类似的完全托管访问数据库的框架,一般用 mybatis 之类的将查询结果转换成 entity 。

这种情况下如果类之间有关联关系,在设计 api 的时候大家一般如何做呢。

比如 User 关联 Department ,在 User 里面是用 departmentId 还是 Department 实体,

如果用 id 属性,在一些情况下需要 department 表的信息,就需要二次查询。

用实体 Department 的情况下(查询 User 时增加 left join department ),是很方便访问关联表的数据,但是会遇到下面两个问题:

  1. 如果 Department 又关联了 Organization 属性呢?Organization 又关联了其他的 Entity 呢, 这样一个查询 User 表的数据的 sql 会关联到很多其他的表,而且很多的 sql 语句都是重复使用的,比如查询 DepartmentOrganization 的列字段和直接查询 Department 实体时的字段是一样的,如果 department 表新增加了字段,这几处的 sql 都要改。

2.

6329 次点击
所在节点    程序员
62 条回复
Vaspike
2022-07-28 10:58:54 +08:00
数据库怎么设计请参考三大范式...
业务代码的话如果不是统计类的需求大概率不需要直接 join,通过关联 key 流式查询相关联实体比较好,用哪个查哪个
hahaFck
2022-07-28 11:07:37 +08:00
@zhao1014 你这个说的有点极端了,怎么变成融合怪了。
KevinBlandy
2022-07-28 11:21:54 +08:00
我一直都是用 jpa ,但是不用 oop 建模,各种关联,延迟加载,更新策略。。。坑太多了。你就按照一张表,一个对象。再配合 QueryDsl 。简直不要太棒了。

我写过一篇关于 querydsl 案例文章,你也许可以参考一下:[https://springboot.io/t/topic/4424]( https://springboot.io/t/topic/4424)
NoKey
2022-07-28 11:29:50 +08:00
按照常规的开发模式,所有表独立,不加关联关系,不加外键,各表之间使用关键字关联,关联关系在代码逻辑体现,查询方式就是 2 种,一种是 join 多表查询;一种是代码里一个一个查出来,再组合
LeegoYih
2022-07-28 11:44:41 +08:00
@hahaFck 如果设计成 user 表中加 department_id ,表示 user 对 department 有依赖,显然,业务上他们之间并不是这种关系。而且一个 user 可能会对应多个 department 。

至于你说的 organization ,和 user 不是直接关系,而是通过 department 间接关联,那么应该是 organization_department_relational 。
OnTheBerlinWall
2022-07-28 11:46:08 +08:00
fkdog
2022-07-28 11:58:18 +08:00
项目规模不大的话,数据库直接 join 什么其实还是很好用的。
瞅了一眼楼上为什么好多不推荐 join 的感觉都没说到点上。

我自己的经验就是:
1.大项目需要分表分库,join 在分库分表的情况下处理起来很麻烦。
2.缓存问题。比如某个订单列表里包含有用户昵称,这个昵称因为是通过 join 查询因此也被缓存起来了,假如某个用户改了昵称,那么很容易会忽略掉这些缓存造成不一致的问题。
3.用业务代码替代数据库 join ,也能方便日后服务化。比如用户系统和订单系统以后做拆分了,vo 需要同时展示订单信息+用户信息,那么就可以根据关联的 id 调用其他服务来获取数据,减少重构成本。( UserDAO.findById -> UserRemoteService->findById )
4.一般情况下,join 是不会直接 select *所有字段的,一般都是按需选字段。不同的业务需要取不同字段的话就要写不同的 join 了,还不如直接 id 直查关联数据,按需选取。

至于你说的多表关联,一般是要求不超过三张表 join 的。
像商品-订单-用户,就是典型的用户-商品多对多关系,订单可以看作是关联表并且额外维护了其他的信息。
但是像角色-角色权限关联表-权限,也是一个多对多关系,但是由于角色-权限本身是紧密耦合的,不会像商品用户那样可以独立作为一个系统,他们的关联表也不需要维护额外的信息,所以这种场景肯定还是 join 更合适。
wxf666
2022-07-28 12:58:36 +08:00
@LeegoYih 即使一对多关系,也『不应该直接关联另一个实体』嘛
superbai
2022-07-28 13:19:07 +08:00
看了下大家说的好像都是 C 端的?如果是内部运营系统或者 B 端的场景,在列表页就是有跨实体筛选、排序或者分页的需求,这种情况下不连表能实现吗?
tvp100
2022-07-28 13:27:59 +08:00
为什么不能 join 多个表呢?如果我根据一个 List 的 User 的 ID 去查另一个东西,那查询不是要查十几次?而我 join 只需要一条 sql 一次查询
yinzhili
2022-07-28 13:50:07 +08:00
都用 mybatis 了,那就是尽量使用 join 来查询你要的字段数据了
TWorldIsNButThis
2022-07-28 13:50:54 +08:00
表小而查询复杂的联表很正常
数据再多的话就上 es
timethinker
2022-07-28 13:52:25 +08:00
思路放开一点,将查询和命令分离开来,这样会清晰很多,表结构也不用为了查询而影响到 OLTP 的处理。基本的思路就是,你不知道将来会有什么查询的需求,在设计表结构的时候,应当根据实际的业务操作来进行设计,这样你在建模 Entity 的时候,就是跟数据库的表结构相对一致的。

我也建议用 JPA 来进行 OLTP 业务类型的建模和操作,用 MyBatis 来进行自定义查询相关的处理,是的,你不用只使用一种技术或者框架,虽然好像你会写更多的代码,但实际上这样做了以后你会发现思想负担会减少很多,也更有信心进行修改和重构。
dqzcwxb
2022-07-28 14:17:23 +08:00
又是一个想把业务逻辑写 sql 里而且疯狂 join 的新开发,这条路每个人都得走一遍哈哈哈哈哈哈哈
zmal
2022-07-28 15:20:07 +08:00
当你在 3 张表以上的 join 加一堆 where...on 时,已经是在 SQL 里写业务了。
联查最大的问题是制约了数据库设计,一般认为 mysql 单表几千万是上限,超过该规模考虑分表。联查的索引不易设计,很容易在业务规模还未扩大时就整出慢 SQL 。
所以三大范式在实际业务中很少遵守,往往是弱耦合 + 宽表的设计思路。数据规模再扩大就上列式存储,不会尝试在关系型数据库死磕。

当然一切都不是绝对的,如果你的 User 表几千条,Department 几十条,Organization 几十条,想怎么 join 都行。但还是建议在代码层解决问题,除非涉及到性能问题。
notwaste
2022-07-28 15:40:12 +08:00
软件设计没有银弹,抛开场景来说没有意义,性能上没有问题的情况下两次或多次查询也没有什么问题,即使避开多次查询进行连表 sql 也一样会出现问题,若性能存在问题的情况下按照描述在数据库设计时就应考虑是否反范式设计存在适当冗余
LeegoYih
2022-07-28 16:38:19 +08:00
@wxf666
根据 OP 的业务场景,一般是如此。应该考虑到「用户系统」和「组织架构」的隔离性,即「用户系统」可以拆出来单独使用,「组织架构」也可以拆出来可以与其他的「用户系统」配合使用,而不需要改造代码(或者说只需要微调)。

如果是商品( SPU )和商品库存( SKU )这种业务,则应该用直接关联,如:在 sku 表中存 spu_id ,因为他们业务上本身就是强关联的,而且一般是处于同一个 domain 中。

@hahaFck
不推荐使用 join ,是因为互联网业务的很多场景下都可能无法使用 join ,例如:
- 微服务:物理隔离
- 分库分表:数据库实例不同
- 数据中台:数据存在中台,只能通过接口方案
- 更换数据库(多数据库):去 Oracle 化、MySQL -> TiDB 、RBD -> KVDB 等,不同数据库语法可能不兼容。

如果没有使用 join ,只需要替换 Repository 层即可,如果使用的是 JPA ,甚至可以不改代码。
l0ve1o24
2022-07-28 16:50:14 +08:00
请教,不用 join 的话,是遍历去查相关数据,还是 in 查相关数据再拼凑回去?
freebird1994
2022-07-28 16:53:14 +08:00
@l0ve1o24 in 可以走索引,遍历 io 开销大得多
zhao1014
2022-07-28 17:36:59 +08:00
@hahaFck 等你入职以后让你维护一堆这种代码你就明白为什么了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/869153

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX