3

DDD 持久化的时候如何避免无效 DB 操作?

 1 year ago
source link: https://www.v2ex.com/t/936712
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

DDD 持久化的时候如何避免无效 DB 操作?

  vczyh · 7 小时 22 分钟前 · 792 次点击

DDD Repository 中的 save(T t) 方法实现 insert 和 update ,如果 t 中只有某个字段发生改变,那么只需更新这个字段即可,而不是更新全部字段,一般即使全部更新的话问题也不是很大,但是如果 t 中有列表或者设计到多张表,这个时候可能增加对 DB 的操作,请问如何解决这种问题?

从网上找到 snapshot 解决方法:

大家有没有什么实践或建议?

第 1 条附言  ·  5 小时 56 分钟前

20 条回复    2023-05-01 20:33:37 +08:00
huijiewei

huijiewei      6 小时 46 分钟前

这个是持久层的基础库应该考虑的事情,每个 ORM 都有动态更新查询的功能
TWorldIsNButThis

TWorldIsNButThis      6 小时 28 分钟前

不清楚 hibernate 有没有相关配置
而且一般这种涉及多张表的也很少有高频次更新操作
vczyh

vczyh      6 小时 0 分钟前

@huijiewei 现在就是需要实现 Repository ,所以遇到这个问题,我感觉 ORM 解决不了这个问题,请大佬赐教,比如这样一个场景:

- save 一个 List<R>
一般是 rList.foreach(r=>save(r)),如果有的 r 没有修改,以上操作明显会导致多余的对 DB 的访问。
rozbo

rozbo      5 小时 55 分钟前

这个问题可以通过和 ai 沟通得到它的看法,我觉得很有道理,ai 认为,性能不能仅从某一个点考虑,要考虑整体,比如是否符合逻辑,是否有容错性和副作用等,如果一味的追求极致的性能,应该直接操作 sql 语句。。。选择了 orm 就要接受它的低效率
vczyh

vczyh      5 小时 37 分钟前

@huijiewei 可能我没有表达清楚。我想表达的是 DDD 对持久化的影响,不是 ORM 批量的问题,DDD 聚合根中的一个 List 属性中的一个元素发生了变化,我实现的时候只想执行一条 update(item),而不是不管元素有没有修改,全部元素都执行一次 update ,即使一些 ORM 会对后者进行优化,我觉得不应该依赖这种,而且还得设置 allowMultiQueries=true 参数。

如果不用 DDD ,其实没有这种无效访问 DB 的问题。
vczyh

vczyh      5 小时 36 分钟前

@rozbo 现在不用 ORM 也会有问题,我这个问题是基于 DDD 的。
huijiewei

huijiewei      5 小时 30 分钟前

@vczyh 如果聚合根里面的一个 List 属性中一个元素单独变化对聚合根没有影响的话,单独用领域对象去更新就好了。

https://insights.thoughtworks.cn/ddd-persist-aggregation/

DDD 这个说实话,没有领域专家介入,光靠程序员非常难。
rozbo

rozbo      5 小时 25 分钟前

@vczyh 个人看法:DDD 就是个理想。。
DDD 还要求不让用导航属性呢,完全按照到 DDD ,可能确实提高了维护性,但是极大的降低了开发效率。
我觉得只要领悟它的思想就成,不必要 100%做到,做到“心中有剑”这一步就够了。
vczyh

vczyh      5 小时 10 分钟前 via iPhone

@rozbo 我现在越来越觉得是你说的这样的,太难实现了,但是他指导思想确实好,请问有推荐的架构没,可以实践的?
vczyh

vczyh      5 小时 4 分钟前 via iPhone

@huijiewei 博文中一个观点挺好的:让持久化入侵到领域服务,这样没有性能问题,整个领域内聚且逻辑可复用,只不过损失了领域不强依赖持久的优点。
Leviathann

Leviathann      5 小时 4 分钟前

确认了一下,hibernate 就是这样的,在事务结束时做 dirty check ,只有变更过的 entity 才会生成对应的 update statement
rozbo

rozbo      4 小时 57 分钟前

@vczyh 我不知道你什么语言,dotnet 下有个框架叫 `abp`是我见过的对 ddd 规范理解最深刻的框架了。它实现了模块化,按照它的架构,项目中的每一个部分都是可以复用的,项目中的每个部分也都是可以替换的,比如可以把数据库从 pgsql 换成 mysql 甚至是 mongodb ,也可以无缝把基于依赖的实现换成基于微服务的实现(这一点我在别的框架完全没见过,可以说是 micro service ready ,原理是抽象了一个 application 层,application 层实现了这个模块的功能接口,同时自动生成了 application client 也实现了这个接口,如果有一天你想换成微服务,只要把 appcation interface 的实现换成 application client ,然后把 application 部署成一个独立的 endpoint 就可以无缝切换,代码都不用改)。
但是,你一眼都可以看到,为了实现这些美好的特性,它的开发效率是极低的,新建一个项目都有七八个细分项目,包括 domain 、domain shared 、application 、application contracts 、application client 、http api 、http host 等等,可以说非常的繁琐。但好在,如果你坚持严格按照它的 DDD 模式,你将有很多这些模块可以复用。。不过这一过程非常痛苦
crysislinux

crysislinux      4 小时 47 分钟前 via Android

我建议做好依赖反转就好了。domain 是最高级的,其他部分都依赖它。其他就不要想太多了。比如数据库我觉得没啥抽象的必要性,只要保证 repository 一级是抽象的就行了
vczyh

vczyh      4 小时 46 分钟前 via iPhone

@rozbo 用的是 Java ,不知道有什么成熟的模式可以妥协一下。
vczyh

vczyh      4 小时 41 分钟前 via iPhone

@crysislinux 我现在想的是把 Repository 改一下,原来希望一个 save 方法把整个聚合根持久化,我现在可以增加多个方法,比如 saveOrderItem(OrderItem)
THESDZ

THESDZ      4 小时 39 分钟前

版本?或者显示的状态标记?
vczyh

vczyh      4 小时 33 分钟前 via iPhone

@THESDZ 这也就是我说的 Diff
huwt

huwt      16 分钟前

@vczyh 我用 fastapi 就是这样做的, 把持久化层的代码引入到 domain 里. 但是会带来一个问题, 难以约束数据类型, 不好做静态检查
huwt

huwt      12 分钟前

@vczyh 关于 ORM 低效读写问题, 之前看过有文章说, DDD 是面向变化, 那么偶尔的低效也无所谓, 重要的是维护状态一致.
这个跟 @rozbo 的说法是一致的.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK