DDD 持久化的时候如何避免无效 DB 操作? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
vczyh
0.05D
V2EX    程序员

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

  •  
  •   vczyh 2023-05-01 13:23:06 +08:00 3763 次点击
    这是一个创建于 946 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    从网上找到 snapshot 解决方法:

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

    第 1 条附言    2023-05-01 14:48:52 +08:00
    30 条回复    2023-05-07 16:16:12 +08:00
    huijiewei
        1
    huijiewei  
       2023-05-01 13:59:36 +08:00
    这个是持久层的基础库应该考虑的事情,每个 ORM 都有动态更新查询的功能
    TWorldIsNButThis
        2
    TWorldIsNButThis  
       2023-05-01 14:17:27 +08:00
    不清楚 hibernate 有没有相关配置
    而且一般这种涉及多张表的也很少有高频次更新操作
    vczyh
        3
    vczyh  
    OP
       2023-05-01 14:44:42 +08:00
    @huijiewei 现在就是需要实现 Repository ,所以遇到这个问题,我感觉 ORM 解决不了这个问题,请大佬赐教,比如这样一个场景:

    - save 一个 List<R>
    一般是 rList.foreach(r=>save(r)),如果有的 r 没有修改,以上操作明显会导致多余的对 DB 的访问。
    rozbo
        4
    rozbo  
       2023-05-01 14:50:10 +08:00
    这个问题可以通过和 ai 沟通得到它的看法,我觉得很有道理,ai 认为,性能不能仅从某一个点考虑,要考虑整体,比如是否符合逻辑,是否有容错性和副作用等,如果一味的追求极致的性能,应该直接操作 sql 语句。。。选择了 orm 就要接受它的低效率
    huijiewei
        5
    huijiewei  
       2023-05-01 14:54:15 +08:00
    @vczyh 批量可以自己优化,https://developer.aliyun.com/article/1157550#slide-45

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

    如果不用 DDD ,其实没有这种无效访问 DB 的问题。
    vczyh
        7
    vczyh  
    OP
       2023-05-01 15:09:35 +08:00
    @rozbo 现在不用 ORM 也会有问题,我这个问题是基于 DDD 的。
    huijiewei
        8
    huijiewei  
       2023-05-01 15:15:03 +08:00
    @vczyh 如果聚合根里面的一个 List 属性中一个元素单独变化对聚合根没有影响的话,单独用领域对象去更新就好了。

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

    DDD 这个说实话,没有领域专家介入,光靠程序员非常难。
    rozbo
        9
    rozbo  
       2023-05-01 15:20:25 +08:00
    @vczyh 个人看法:DDD 就是个理想。。
    DDD 还要求不让用导航属性呢,完全按照到 DDD ,可能确实提高了维护性,但是极大的降低了开发效率。
    我觉得只要领悟它的思想就成,不必要 100%做到,做到“心中有剑”这一步就够了。
    vczyh
        10
    vczyh  
    OP
       2023-05-01 15:34:38 +08:00 via iPhone
    @rozbo 我现在越来越觉得是你说的这样的,太难实现了,但是他指导思想确实好,请问有推荐的架构没,可以实践的?
    vczyh
        11
    vczyh  
    OP
       2023-05-01 15:41:34 +08:00 via iPhone
    @huijiewei 博文中一个观点挺好的:让持久化入侵到领域服务,这样没有性能问题,整个领域内聚且逻辑可复用,只不过损失了领域不强依赖持久的优点。
    Leviathann
        12
    Leviathann  
       2023-05-01 15:41:35 +08:00
    确认了一下,hibernate 就是这样的,在事务结束时做 dirty check ,只有变更过的 entity 才会生成对应的 update statement
    rozbo
        13
    rozbo  
       2023-05-01 15:48:06 +08:00
    @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
        14
    crysislinux  
       2023-05-01 15:58:14 +08:00 via Android
    我建议做好依赖反转就好了。domain 是最高级的,其他部分都依赖它。其他就不要想太多了。比如数据库我觉得没啥抽象的必要性,只要保证 repository 一级是抽象的就行了
    vczyh
        15
    vczyh  
    OP
       2023-05-01 15:58:54 +08:00 via iPhone
    @rozbo 用的是 Java ,不知道有什么成熟的模式可以妥协一下。
    vczyh
        16
    vczyh  
    OP
       2023-05-01 16:03:55 +08:00 via iPhone
    @crysislinux 我现在想的是把 Repository 改一下,原来希望一个 save 方法把整个聚合根持久化,我现在可以增加多个方法,比如 saveOrderItem(OrderItem)
    THESDZ
        17
    THESDZ  
       2023-05-01 16:06:14 +08:00
    版本?或者显示的状态标记?
    vczyh
        18
    vczyh  
    OP
       2023-05-01 16:12:25 +08:00 via iPhone
    @THESDZ 这也就是我说的 Diff
    huwt
        19
    huwt  
       2023-05-01 20:29:10 +08:00
    @vczyh 我用 fastapi 就是这样做的, 把持久化层的代码引入到 domain 里. 但是会带来一个问题, 难以约束数据类型, 不好做静态检查
    huwt
        20
    huwt  
       2023-05-01 20:33:37 +08:00
    @vczyh 关于 ORM 低效读写问题, 之前看过有文章说, DDD 是面向变化, 那么偶尔的低效也无所谓, 重要的是维护状态一致.
    这个跟 @rozbo 的说法是一致的.
    echoless
        21
    echoless  
       2023-05-01 21:11:41 +08:00
    @Leviathann #12 我观察过 python 的 sqlalchemy 也是类似的机制, 生成的 sql 是很精简的.
    vczyh
        22
    vczyh  
    OP
       2023-05-02 18:13:13 +08:00 via iPhone
    @huwt 是的,有时候性能和可维护性要平衡一下
    vczyh
        23
    vczyh  
    OP
       2023-05-02 18:14:52 +08:00 via iPhone
    @huwt 就算让他进来也得统一通过 Repository ,不能把 dao 和 数据库实体入侵进来
    vczyh
        24
    vczyh  
    OP
       2023-05-02 18:16:31 +08:00 via iPhone
    @echoless Hibernate 没研究过,我的想法是更倾向于不依赖具体框架和语言
    echoless
        25
    echoless  
       2023-05-02 18:40:26 +08:00 via Android
    @vczyh 这个从 object 到 db 的操作 如果你用了 orm 就是 orm 的事情 你不用管细节
    nielinjie
        26
    nielinjie  
       2023-05-03 11:53:47 +08:00
    实践中很难到关注到这个的程度。换句话说,此种调优几乎不会有必要。
    如果有要做,需要考虑一致性的问题。
    在多读多写的情况下,diff 后再写跟整个对象覆盖写的语意不同。需要根据业务要求进行区别。
    857681664
        27
    857681664  
       2023-05-03 13:19:03 +08:00
    看起来比较容易实现的是把 repo 层上升到 domain 层,然后自己做 diff ,再 update
    kkbblzq
        28
    kkbblzq  
       2023-05-03 22:30:19 +08:00
    感觉用 DDD 主要还是借用思想,具体还是要根据当前公司 /项目的情况来进行适配的,并不是说存储层接口定义只能这样设计。。我上家公司推 DDD 一年之后,基本项目上都做了简化的,完全按 DDD 那套来要增加不少开发成本。
    vczyh
        29
    vczyh  
    OP
       2023-05-04 09:21:26 +08:00
    @kkbblzq 请教一下,请问做了哪些简化呢,想学习一下。
    vczyh
        30
    vczyh  
    OP
       2023-05-07 16:16:12 +08:00
    @nielinjie 这个角度很不错
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     967 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 19:23 PVG 03:23 LAX 11:23 JFK 14:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86