4

我正在研究DDD和事件源的編程。如何在DDD中管理域邏輯和事件之間的事務?

我看到一個例子,當域邏輯被調用時(例如Order.placeOrder())它會發佈一個事件(例如OrderPlaced)。事件將作爲事件存儲發送到MQ。

域邏輯(Order.placeOrder())應該是原子API,如果使用Spring作爲事務管理器,它應該有@Transactional註釋。

現在我的問題是:

  1. 如何確保DB變化和事件發送是在同一事務中?即如果在將數據提交到數據庫時出現任何錯誤,則該事件不應發送到MQ。

    我知道有類似XA或2階段提交的解決方案來強制數據庫更新並在同一事務中發送MQ消息。但似乎現在並沒有被廣泛使用。

  2. 如果仍然使用Spring @Transactional註釋並且沒有XA,那麼在事務成功提交後我們可以做一些邏輯嗎?最佳做法是什麼?

回答

7

以下兩個屬性必須堅持有一個可靠的系統:

  • P1:發佈域事件MUST描述,真正發生了變化(即確保沒有鬼事件開始飛行周圍)。
  • P2:更改觸發域事件的DB 必須導致發佈事件(即不會丟失事件)。

主要有以下幾種方法可以實現,所有這一切,我要麼使用自己或看到在項目中使用:

  1. 使用使用相同的數據庫作爲消息傳遞基礎結構應用程序,以便可以使用單個事務。當一個非常簡單的消息傳遞基礎架構足夠時,這個解決方案是可行的,並且團隊決定自己構建它。

  2. 使用2階段提交。我沒有這樣的印象,這不再使用,但也許它少談論,因爲它不是花哨的技術...

  3. 使用一些聰明的技巧,以確保兩個條件成立。例如。與我所說的雞和雞蛋解決方案:

    • 總是先同步發佈事件,然後堅持到數據庫。這確保P2持有。
    • 然後使用事件處理器檢查事件流並檢查是否可以在DB中找到事件。如果不是,請從流中移除該事件。這確保了P1成立。

解決方案3需要系統的每個部分使得故障行爲方面的擔保精心設計和審查,所以它可能是最困難的一個得到的權利。但它一旦工作,也是一個非常優雅的解決方案。

順便說一下,我不同意Spring註釋應該添加到域對象,而是添加到相應的應用程序服務。這只是作爲一個附註。

+0

感謝您的回覆。使用與事件相同的數據庫是事務管理的一種簡單方法。我認爲這對內部事件是有好處的。但是,如果我們需要發佈外部事件以供大量用戶使用。處理案件的做法是什麼?我們是否需要額外的調度程序將事件從數據庫事件存儲移動到ESB產品(如MQ)? –

+0

@RandyHuang這取決於你的環境。您可以使用調度程序,也可以在原始事務結束時觸發「檢查新的域事件」。 – theDmi