CRUD 工程师提问:最佳实践是把逻辑放在数据库中还是后端代码中 ?

2018-12-08 19:57:52 +08:00
 V2XEX

crud 搞久了,最近坐下来想些问题就发现脑子有点乱。 假如现在有这么一个按类别查询某用户未读帖子数量场景:

有 2 张表
用户表 user,字段: 用户唯一标识符:uuid
帖子表 post,字段: 帖子类别:type ; 帖子已读用户:readers (用户每打开一个帖子就往这个字段写入用户 uuid,并以逗号分隔)

Java 代码中有对应的实体类,orm 使用 Spring Data Jpa。

现在需要按类别查询某用户未读帖子数量,有两个方案:
1、直接查出所有帖子的类型和已读用户字段,然后用 Java8 的 Stream.filter、Collectors.groupingBy 来过滤、分类,直接给前端一个返回一个 Map (体现了 orm 的思想……)
2、用包含 couting、not like、group by 等关键字的 sql 直接查出结果,直接给前端返回一个 Set<map>。

如果使用方案 1,那么项目这部分 Java 代码应该放在哪里( service or controller )?项目结构应该怎么划分呢?

虽然问题很小,不知道这算是钻牛角尖不……请有经验的 Ver 指教下

6649 次点击
所在节点    Java
42 条回复
raphael008
2018-12-08 20:01:14 +08:00
方案 1 放 manager 层里
xy90321
2018-12-08 20:04:23 +08:00
除非你用的数据库性能很差或者不提供类似功能语法的支持,否则我看不出全拿出来有什么好处。特别是你的数据量稍微大一点的时候,那已经不是蛋疼而是蛋碎了。(前提是如果内存和磁盘还没爆炸的话)

更重要的是,很多复合 SQL 语法你要自己在 Java 端实现一遍那简直就是…
tomczhen
2018-12-08 20:08:40 +08:00
给钱少、工期短,方案 1 就是最佳实践。

给钱多、工期足,方案 2 就是最佳实践,顺便弄点高大上的技术词汇,什么分布式、中间件都给整上。
Inside
2018-12-08 20:09:30 +08:00
帖子已读用户放到数组里,execute me ?对关系的理解和认识本身就有问题。
这种认识直接导致了方案一这种瞎搞的方案。
tomczhen
2018-12-08 20:09:41 +08:00
@tomczhen 说反了......
V2XEX
2018-12-08 20:17:59 +08:00
@xy90321 其实就算不全拿出来,统计的根本逻辑也是在数据库中实现了,两个做法的区别就是统计的逻辑放在哪里
V2XEX
2018-12-08 20:18:45 +08:00
@Inside 那就这个功能来说,数据库应该如何设计呢?请指教……
liuhuansir
2018-12-08 20:32:52 +08:00
应该再加一张已读帖子与用户多对多的表,用帖子总数减去已读数得到结果,一个业余后端的建议
MegrezZhu
2018-12-08 20:33:24 +08:00
首先既然是 SQL 数据库的话,这样设计表是有问题的…应该抽出一个用户已读帖子的表( userid+postid ),然后做一些外键 /索引,这样直接通过 SQL 查询的时候数据库能对查询做优化,不用读取全部数据。第一种方法在数据量大的时候基本不现实。
可以去看看数据库范式,挺经典的理论。
xiangyuecn
2018-12-08 20:37:31 +08:00
最佳实践是根据实际情况合理搭配和选择。。。算了,还是先把那个设计这个表结构的打死了再谈后面的吧,哈哈
ruandao
2018-12-08 20:45:56 +08:00
这个要考虑 数据库的 IO 成本和计算量
houyujiangjun
2018-12-08 20:51:20 +08:00
这是一个领域模型驱动的问题.
V2XEX
2018-12-08 21:21:41 +08:00
@MegrezZhu 但是这么设计的话这张中间表的记录数很容易就是几何级数增长啊,而且当有删除需求时这张表将承载更多任务
V2XEX
2018-12-08 21:22:50 +08:00
@xiangyuecn 等我意识到这么设计表有多蠢的时候就会扇自己两巴掌
MegrezZhu
2018-12-08 21:26:28 +08:00
@V2XEX 已有的帖子表 post 里面本来就存了每个帖子的已读用户,把它抽出来并不会增加多少负担。数据量级是没有变化的。
V2XEX
2018-12-08 21:46:35 +08:00
@MegrezZhu 有 n 个帖子,m 个用户,那么这张中间表至多就会有 m × n 条记录,以后每新发一个帖子至多会增加 m 条记录。还需要考虑删除情况……这样的开销对于原来直接将用户 uuid 写入帖子表某个字段来说不知道哪个更优?
chanchan
2018-12-08 21:55:26 +08:00
我的习惯是 2
azzwacb9001
2018-12-08 22:25:34 +08:00
好问题。我是一个菜鸟,但我觉得方案 2 是比较合理的方案。如果不考虑具体的场景,那我觉得这个问题可以这么看:
如果从数据库中取出来的数据,没有在中间层进行二次加工的需求,那就使用方案 2 ;如果一些从数据库中用比较复杂的 SQL 语句取出来的数据,还可能二次加工或者供多方使用,那就用方案 1.

不知道我有没有理解楼主的问题= =我没搞过 JAVA
MegrezZhu
2018-12-08 22:31:58 +08:00
@V2XEX 直接将 uuid 写入帖子表的话,帖子表里面不也一样会是至多 m × n 个 uuid 吗,顶多减少了帖子 tid 的存储空间,所以我才说不会有数量级上的差距。
而且考虑删除情况的话,考虑在某个帖子下删除某个用户的阅读记录(呃,为啥会有这个需求,还是我理解错了?),首先就会有 O(n)的查询复杂度。相对地如果是采用访问记录表的话,依靠索引可以近似地达到 O(1)的复杂度。
如果是删帖带来的删除所有该帖子下的阅读记录的话,方法 1 可能会略有优势,但访问记录表依然可以利用索引高效删除,而且删除操作相对也不多。
yfl168648
2018-12-08 22:34:44 +08:00
搞个表,类别、用户、未读数,首次用脚本生成此表数据,然后改造读帖子的代码,如果首次读,未读数减一。这样如何?

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

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

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

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

© 2021 V2EX