我正在研究DDD和事件源中的编程。
我看到一个例子,当调用域逻辑时(例如Order.placeOrder()
),它会发布一个事件(例如OrderPlaced
)。事件将作为事件存储发送到MQ。
域逻辑(Order.placeOrder()
)应该是一个原子API,如果使用Spring作为事务管理器,它应该有@Transactional
注释。
现在我的问题是:
如何确保数据库更改和事件发送在同一个事务中?即,如果在将数据提交到DB时出现任何错误,则该事件永远不应发送给MQ。
我知道有像XA或2阶段提交这样的解决方案来强制数据库更新并在同一事务中发送MQ消息。但现在似乎没有被广泛使用。
如果仍然使用Spring @Transactional
注释而没有XA,那么在事务成功提交后我们可能会做一些逻辑吗?这样做的最佳做法是什么?
答案 0 :(得分:9)
必须拥有以下两个属性才能拥有可靠的系统:
实现这一目标有以下几种可能性,所有这些都是我自己使用过或看到过在项目中使用过的:
使用与应用程序使用相同数据库的消息传递基础结构,以便可以使用单个事务。当一个非常简单的消息传递基础设施足够时,该解决方案是可行的,并且团队决定自己构建它。
使用2阶段提交。我不会觉得这种情况不再使用了,但也许它不那么受欢迎了,因为它并不是一种奇特的技术......
使用一些聪明的技巧来确保两个条件都成立。例如。用我称之为鸡肉和鸡蛋的解决方案:
解决方案3需要仔细设计并检查系统的每个部分在故障行为方面所做的保证,因此可能是最难实现的。但是一旦它起作用,它也是一个非常优雅的解决方案。
顺便说一下,我并不同意将Spring注释添加到域对象中,而是添加到相应的应用服务中。这仅作为旁注。