如何在DDD中管理域逻辑和事件之间的事务?

Ran*_*ang 6 java spring domain-driven-design transactions event-handling

我正在研究DDD和事件源中的编程.

我看到一个例子,当调用域逻辑时(例如Order.placeOrder())它会发布一个事件(例如OrderPlaced).事件将作为事件存储发送到MQ.

域逻辑(Order.placeOrder())应该是一个原子API,@Transactional如果使用Spring作为事务管理器,它应该有注释.

现在我的问题是:

  1. 如何确保数据库更改和事件发送在同一个事务中?即如果在将数据提交到DB时出现任何错误,则该事件永远不应发送给MQ.

    我知道有像XA或2阶段提交这样的解决方案来强制DB更新并在同一事务中发送MQ消息.但似乎现在还没有广泛使用.

  2. 如果仍然使用Spring @Transactional注释而没有XA,那么在事务成功提交后我们可能会做一些逻辑吗?这样做的最佳做法是什么?

the*_*Dmi 9

必须具备以下两个属性才能拥有可靠的系统:

  • P1:发布的域事件必须描述真正发生的变化(即确保没有鬼事件开始飞来飞去).
  • P2:对触发域事件的DB的更改必须导致发布事件(即不丢失事件).

实现这一目标有以下几种可能性,所有这些都是我自己使用过或看到过在项目中使用过的:

  1. 使用与应用程序使用相同数据库的消息传递基础结构,以便可以使用单个事务.当一个非常简单的消息传递基础结构足够时,该解决方案是可行的,并且团队决定自己构建它.

  2. 使用2阶段提交.我没有这种印象不再使用,但也许它不那么受欢迎了,因为它不是花哨的技术......

  3. 使用一些聪明的技巧来确保两种条件都成立.例如我称之为鸡肉和鸡蛋的解决方案:

    • 始终首先同步发布事件,然后保留到数据库.这确保P2成立.
    • 然后使用事件处理器检查事件流并检查是否可以在数据库中找到事件.如果没有,请从流中删除该事件.这确保P1成立.

解决方案3需要仔细设计并检查系统的每个部分在故障行为方面所做的保证,因此可能是最难实现的.但是一旦它起作用,它也是一个非常优雅的解决方案.

顺便说一下,我不同意将Spring注释添加到域对象,而是添加到相应的应用服务.这仅作为旁注.