Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在DDD中管理域逻辑和事件之间的事务?_Java_Spring_Transactions_Event Handling_Domain Driven Design - Fatal编程技术网

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

Java 如何在DDD中管理域逻辑和事件之间的事务?,java,spring,transactions,event-handling,domain-driven-design,Java,Spring,Transactions,Event Handling,Domain Driven Design,我正在研究DDD和事件源的编程 我看到一个例子,当一个域逻辑被调用时(例如,Order.placeOrder()),它将发布一个事件(例如,OrderPlaced)。事件将作为事件存储发送到MQ 域逻辑(Order.placeOrder())应该是一个原子API,如果使用Spring作为事务管理器,它应该具有@Transactional注释 现在我的问题是: 如何确保数据库更改和事件发送在同一事务中?i、 e.如果在将数据提交到数据库时出现任何错误,则事件不应发送到MQ 我知道有类似XA或2阶段

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

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

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

现在我的问题是:

  • 如何确保数据库更改和事件发送在同一事务中?i、 e.如果在将数据提交到数据库时出现任何错误,则事件不应发送到MQ

    我知道有类似XA或2阶段提交的解决方案,可以强制在同一事务中更新数据库并发送MQ消息。但现在似乎还没有被广泛使用

  • 如果仍然使用Spring
    @Transactional
    注释,并且没有XA,那么在事务成功提交之后,我们是否可以执行一些逻辑?这样做的最佳实践是什么


  • 以下两个属性必须保持,才能拥有可靠的系统:

    • P1:已发布的域事件必须描述实际发生的更改(即确保没有鬼事件开始四处传播)
    • P2:对触发域事件的DB所做的更改必须导致事件被发布(即不要丢失事件)
    要实现这一点,有以下几种可能性,所有这些都是我自己或在项目中看到的:

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

  • 使用2阶段提交。我不认为这已经不再被使用了,但也许人们很少谈论它,因为它不是什么新奇的技术

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

    • 始终先同步发布事件,然后将其持久化到数据库。这确保了P2的有效性
    • 然后使用事件处理器检查事件流并检查是否可以在数据库中找到事件。如果不是,则从流中删除事件。这确保了P1的有效性
  • 解决方案3需要仔细设计和审查系统每个部分在故障行为方面所做的保证,因此这可能是最难做到的。但一旦成功,这也是一个非常优雅的解决方案


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

    谢谢您的回复。使用与事件相同的DB确实是事务管理的一种简单方法。我认为这对于内部事件是很好的。但是,如果我们需要发布一个外部事件以供大量订阅者使用。处理案件的做法是什么?我们是否需要一个额外的调度器来将事件从DB事件存储区移动到像MQ这样的ESB产品上?@RandyHuang,这取决于您的环境。您可以使用调度程序,也可以在原始事务结束时触发“检查新域事件”。