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



我正在学习DDD和事件源的编程。

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

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

现在我的问题是:

  1. 如何确保DB更改和事件发送在同一事务内?例如,如果在向DB提交数据时出现任何错误,则事件永远不应发送到MQ。

    我知道有像XA或2阶段提交这样的解决方案来强制DB更新并在同一事务中发送MQ消息。

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

一个可靠的系统必须具备以下两个属性:

  • P1:已发布的域事件必须描述真正发生的变化(即确保没有幽灵事件开始四处飞行)。
  • P2:触发域事件的DB更改必须导致事件被发布(即不要丢失事件)。

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

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

  2. 使用2阶段提交。我不觉得它已经不再被使用了,但也许它很少被谈论,因为它不是一项花哨的技术…

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

      总是先同步发布事件,然后持久化到DB。这确保了P2保持不变。
  4. 然后使用事件处理器来检查事件流并检查是否可以在DB中找到事件。如果没有,则从流中删除该事件。这确保P1保持。

解决方案3需要仔细设计和审查系统的每个部分在故障行为方面所做的保证,因此它可能是最难正确处理的。但这也是一个非常优雅的解决方案,一旦它工作。

顺便说一下,我不同意应该把Spring注解添加到域对象中,而应该添加到各自的应用服务中。这只是一个旁注。

相关内容

  • 没有找到相关文章

最新更新