【问题标题】:In Domain Driven Design, may a transaction modify more than one aggregate?在领域驱动设计中,一个事务可以修改多个聚合吗?
【发布时间】:2015-01-29 18:57:36
【问题描述】:
在“领域驱动设计:解决软件核心的复杂性”中,Evans 定义
聚合是一组关联对象,我们将其视为一个单元,用于数据更改。
显然,这意味着必须在单个事务中更新聚合。
但是,一个事务必须只更新一个聚合吗?如果有,为什么?
我的研究
我问是因为,在“实施领域驱动设计”,第 360 页,弗农写道:
引用聚合和被引用聚合不得在同一事务中修改。在单个事务中只能修改一个或另一个。
但没有给出这条规则的理由。
我了解,如果业务规则需要单个事务,这表示隐藏的不变量,这将要求实体是同一聚合的一部分。但如果业务不关心,而开发人员只是觉得方便怎么办?
在第 437 页,弗农还写道:
注意不要仅仅因为它在单元测试环境中工作而过度使用在单个事务中提交对多个聚合的修改的能力。如果您不小心,在开发和测试中运行良好的方法可能会因为并发问题而在生产中严重失败。
那些并发问题是什么?
【问题讨论】:
标签:
java
transactions
domain-driven-design
aggregateroot
【解决方案1】:
乐观并发通常用于在存在争用的环境中避免数据丢失。
让我们看看使用该机制会导致并发异常:
- 用户 Foo 加载聚合 A,版本为 V1。
- 用户栏加载聚合 A,版本为 V1。
- 用户 Foo 更改聚合 A 并保持(版本为
增加到 V2)。
- 用户栏更改聚合 A 并尝试保持但将获得
并发异常,因为他的更改基于 V1,但是
聚合现在是 V2。
如果您允许在每个事务中修改多个聚合,则会增加并发异常的风险,这可能会损害系统的可扩展性,直至使其无法使用。
聚合根 (AR) 是事务边界,其中不变量是事务一致的,因此如果您发现自己尝试修改多个 AR相同的交易意味着您的 AR 边界可能是错误的,并且您可能错过了将隐含概念明确化的机会。
但是,请注意,在单个事务中创建多个 AR 应该没有问题。
设计 AR 时的常见错误是通过过于重视语句中的关系词来创建大型集群,例如:
“帖子有 cmets”
如果没有需要这种组合的不变执行,则没有理由将 Post 和 Comment 聚集在一起。两位作者是否应该同时在同一评论上发帖导致并发异常?答案可能是否定的,具体取决于您的域,但如果Post 包含Comment 的集合,则它会。
但如果业务不关心,开发人员只需找到它怎么办
方便吗?
好吧,如果企业不关心他们的系统由于糟糕的设计决策而无法扩展,我想这是他们的选择,但开发人员不应该养成为方便而设计的习惯。 DDD 是关于按原样对领域进行建模,而不是按照方便建模的方式。