DDD - 如何处理“返回域事件”模式中的事务?

时间:2017-11-10 12:20:28

标签: domain-driven-design domain-events

在DDD文章中,返回域事件模式被描述为管理域事件的一种方式。从概念上讲,聚合根目录会保留一个域事件列表,当您对其执行某些操作时会填充这些事件。

当聚合根的操作完成后,数据库事务在应用程序服务层完成,然后,应用程序服务迭代域事件,调用事件调度程序来处理这些消息。

我的问题是关于我们此时应该处理交易的方式。 Event Dispatcher是否应负责管理其处理的每个事件的新事务?或者,应用程序服务是否应该在域事件迭代内管理事务,并调用域事件调度程序?当调度程序使用像RabbitMQ这样的基础架构机制时,问题是无关紧要的,但是当域事件在进程中处理时,它就是。

与我的问题有关的子问题。您对使用ORM钩子(即:IPostInsertEventListener,IPostDeleteEventListener,NHibernate的IPostUpdateEventListener)在聚合根上启动域事件迭代而不是在应用程序服务中手动执行它有什么看法?它是否会增加过多的耦合?它是否更好,因为它不需要在每个用例中编写相同的代码(在聚合上循环的域事件,如果它不在调度程序内,可能会创建新的事务)?

2 个答案:

答案 0 :(得分:3)

  

我的问题是关于我们此时应该处理交易的方式。 Event Dispatcher是否应负责管理其处理的每个事件的新事务?或者,应用程序服务是否应该在域事件迭代内管理事务,并调用域事件调度程序?

你在这里问的是这个问题的一个特殊版本:我们是否应该在一次交易中更新多个聚合?

你可以找到许多断言答案是"不是"。例如,Vaughn Vernon (2014)

  

正确设计的聚合是可以以任何方式修改的聚合,其不变量在单个事务中完全一致。并且在所有情况下,正确设计的有界上下文仅修改每个事务的一个聚合实例。

Greg Young倾向于更进一步,指出遵守此规则允许您按聚合ID对数据进行分区。换句话说,聚合边界是对数据组织方式的明确表达。

所以,最好的办法是尝试安排更复杂的编排,以便每个聚合在自己的交易中更新。

  

我的问题与我们处理在初始交易完成后更改初始聚合后发送的事件的交易方式有关。必须处理域事件,并且其进程可能需要更改另一个聚合。

是的,所以如果我们要改变另一个聚合,那么(根据上面的建议)应该是一个新的交易来改变聚合。换句话说,它不是确定我们是否需要另一个事务的域事件的路由 - 事件处理程序的选择决定了我们是否需要另一个事务。

答案 1 :(得分:2)

仅仅因为事件处理在进程中发生并不意味着原始应用程序服务必须协调由于事件而发生的所有事务。

例如,如果我们通过Observable模式进行进程内事件处理,则每个Observer将负责在需要时创建自己的事务。

  

您对使用ORM挂钩有何看法(即:   IPostInsertEventListener,IPostDeleteEventListener,   NHibernate的IPostUpdateEventListener)启动域事件   迭代聚合根而不是手动执行它   申请服务?

这不会发生在原始数据库事务期间,有效地将所有内容转换为立即一致性(如果事件是在进程中处理的话)吗?