2013-07-02 103 views
10

爲了簡化我的問題,我有春/ RabbitMQ的:事務管理

應用1與@Transactionnal方法的createUser():

  • 插入數據庫中的新用戶
  • 在RabbitMQ的添加異步消息以便用戶收到通知郵件
  • (可能有一些額外的代碼,但不多)

應用2與RabbitMQ的消息consummer

  • 在實時的郵件隊列Consummes信息數據庫
  • 讀取郵件內容發送郵件

的問題是,有時, App2甚至在App1上提交事務之前,App2會嘗試使用RabbitMQ消息。這意味着App2無法讀取數據庫上的郵件數據,因爲用戶尚未創建。

一些解決方案可能是:

    上應用2
  • 使用READ_UNCOMMITED隔離級別
  • 添加在RabbitMQ的消息傳遞一定的延遲(或在consummer一些RetryTemplate)
  • 改變我們發送電子郵件的方式...

我見過有一個在Spring的RabbitTransactionManager,但我不明白它應該如何w掃。事務處理內部的東西似乎總是有點難以理解,文檔也沒有太多幫助。


有沒有辦法做這樣的事情?

  • 添加消息到隊列的RabbitMQ在@Transactionnal方法
  • 當事務結束,該消息將提交給隊列,並且改變將提交給數據庫
  • 所以該消息數據庫交易結束前無法完成

怎麼樣?而且,如果我發送同步RabbitMQ消息而不是異步消息,則需要做些什麼呢?它會阻止等待響應的線程嗎? 因爲我們爲不同的用戶發送同步和異步消息。

+0

我說得對,這兩個應用程序使用來自同一隊列中的消息? – pinepain

+0

沒有,應用1將消息隊列中,應用2在該隊列 –

+0

你管理以某種方式解決這個問題消耗的消息?我面臨同樣的問題。 –

回答

1

我並不十分熟悉@Transactionnal和spring,但是在AMQP中,標準的消息隊列並不是事務操作,所以你必須在db中存儲數據(如果db連接是事務性的 - 提交事務)並且只有在發送消息給經紀人。

正確的工作流找我像App1: createUser -> notifyUser; App2: listenForNotifications

1

我知道這是晚了,但我有同樣的問題,因爲我當時的@Transactional瞭解有限。所以這對於你偶然發現的其他人來說更是如此。

當使用@Transactional將數據保存到數據庫中保存到數據庫中犯規竟發生,直到該方法返回,而不是當保存被調用。

所以,如果你有一個像

@Transactional(readOnly=false) 
public void save(Object object) { //Object should be one of your entities 
    entityManager.persist(object); //or however you have it set up 
    rabbitTemplate.convertAndSend(message); //again - however yours is 
} 

的方法即使壽你調用該對象的堅持你把隊列中的消息之前,該堅持實際上不會發生,直到該方法返回,從而導致在方法返回之前和的數據實際上是在數據庫中之前被放入隊列中的消息。

嵌套@Transactional方法(不是直接向前)可以在save()方法返回後將消息放入隊列。但是你不能把隊列中的消息,並希望它不會被消耗掉。一旦它消失了。所以如果需要的話,延遲將它放在隊列中。

如果要接收來自隊列的同步方式的響應。在我的函數的例子 - 你可以做到這一點,但它只會使它需要較長時間才能真正持久化數據,因爲它會等待來自工人的響應方法才能返回,實際上仍然存在的數據。 (還要記住,接收來自排隊消息的響應具有超時)。

所以我的建議是不要把那些2個操作在同一@Transactional