简体   繁体   English

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

[英]How manage transaction between domain logic and events in DDD?

I am studying on the programming in DDD and event source. 我正在研究DDD和事件源中的编程。

I saw one example that when a domain logic was called (eg Order.placeOrder() ) it would publish an event (eg OrderPlaced ). 我看到一个例子,当一个域逻辑被调用时(例如Order.placeOrder() ),它会发布一个事件(例如OrderPlaced )。 And the event would be sent to MQ as the event store. 事件将作为事件存储发送到MQ。

The domain logic ( Order.placeOrder() ) should be an atomic API, and it should have @Transactional annotation if using Spring for the transaction manager. 域逻辑( Order.placeOrder() )应该是一个原子API,如果使用Spring作为事务管理器,它应该有@Transactional注释。

And now my question is: 现在我的问题是:

  1. How to make sure the DB change and event sending are within the same transaction? 如何确保数据库更改和事件发送在同一个事务中? ie If there any error when committing data into DB, the event should never send to MQ. 即如果在将数据提交到DB时出现任何错误,则该事件永远不应发送给MQ。

    I know that there is solution like XA or 2 phase commit to force the DB update and sending MQ messages within the same transaction. 我知道有像XA或2阶段提交这样的解决方案来强制DB更新并在同一事务中发送MQ消息。 But seems it is not widely used nowadays. 但似乎现在还没有广泛使用。

  2. If still using Spring @Transactional annotation and no XA, is it possible that we do some logic after the transaction is committed successfully? 如果仍然使用Spring @Transactional注释而没有XA,那么在事务成功提交后我们是否可能会执行某些逻辑? What is the best practice to do that? 这样做的最佳做法是什么?

The following two properties must hold to have a reliable system: 必须具备以下两个属性才能拥有可靠的系统:

  • P1: Published domain events MUST describe a change that really happened (ie make sure no ghost events start flying around). P1:发布的域事件必须描述真正发生的变化(即确保没有鬼事件开始飞来飞去)。
  • P2: Changes to the DB that trigger domain events MUST result in an event being published (ie don't lose events). P2:对触发域事件的DB的更改必须导致发布事件(即不丢失事件)。

There are the following possibilities to achieve this, all of which I've either used myself or seen being used in a project: 实现这一目标有以下几种可能性,所有这些都是我自己使用过或看到过在项目中使用过的:

  1. Use a messaging infrastructure that uses the same database as your application, so that a single transaction can be used. 使用与应用程序使用相同数据库的消息传递基础结构,以便可以使用单个事务。 This solution is viable when a very simple messaging infrastructure suffices, and the team decides to build it themselves. 当一个非常简单的消息传递基础结构足够时,该解决方案是可行的,并且团队决定自己构建它。

  2. Use 2 phase commits. 使用2阶段提交。 I don't have the impression that this is not used anymore, but maybe it's less talked about, because it isn't fancy technology... 我没有这种印象不再使用,但也许它不那么受欢迎了,因为它不是花哨的技术......

  3. Use some clever trickery to ensure both conditions hold. 使用一些聪明的技巧来确保两种条件都成立。 Eg with what I call the chicken and egg solution: 例如我称之为鸡肉和鸡蛋的解决方案:

    • Always publish events synchronously first, then persist to the DB. 始终首先同步发布事件,然后保留到数据库。 This ensures P2 holds. 这确保P2成立。
    • Then use an event processor that inspects the event stream and checks whether an event can be found in the DB. 然后使用事件处理器检查事件流并检查是否可以在数据库中找到事件。 If not, remove the event from the stream. 如果没有,请从流中删除该事件。 This ensures P1 holds. 这确保P1成立。

Solution 3 requires careful design and review of the guarantees each part of the system makes in terms of failure behavior, so it is probably the most difficult one to get right. 解决方案3需要仔细设计并检查系统的每个部分在故障行为方面所做的保证,因此可能是最难实现的。 But it is also a very elegant solution, once it works. 但是一旦它起作用,它也是一个非常优雅的解决方案。

By the way, I don't agree that Spring annotations should be added to domain objects, but rather to the respective app services. 顺便说一下,我不同意将Spring注释添加到域对象,而是添加到相应的应用服务。 This only as a side note. 这仅作为旁注。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM