2012-10-27 47 views
1

我將嘗試描述我試圖解決的問題。我意識到我開發的一個應用程序執行的Spring事務管理很差。我在DAO接口方法(CRUD)上定義的事務使用聲明式方法,而不是服務層方法。這是一個web應用程序,它執行某種消息處理,並且多個線程同時在相同的消息實例上運行。以下是典型序列中的步驟:關於春季交易管理的建議重新設計

  1. 消息在T1(事務1)中創建並放入出站隊列。 T1終止。
  2. 消息由隊列中的不同線程獲取,隨着發送時間和一些其他信息發送和更新。消息對象的屬性被設置並調用dao.update(m),t2開始。
  3. 在t2提交之前,收到傳送報告,並且Tread3通過在db中找到它(在步驟1中保存),更新其狀態屬性並調用dao.upate(m)來開始處理相同的消息對象,以便t3在t2仍然進行中。
  4. 另一個線程(線程4)通過在t4中再次更改它的狀態來進一步處理相同的消息對象。

不時發生的結果是從t2開始的更改丟失,發送時間在db中爲空。 我需要幫助確定如何改進應用程序設計,並通過防止同時處理相同的消息來消除此問題。

  1. 我應該集中精力重新設計交易(使用它的服務水平,而不是DAO),並使用序列化隔離級別(或其他方式)或

  2. 我應該使用JPA實體管理器鎖定?

應用程序使用spring 3和JPA2與hibernate實現。

+0

郵件是如何發送的? JMS?網絡服務?其他?你可以讓全局分佈式事務的這部分(在JMS的情況下)?如果不是,那麼您是不是應該在T2完成後簡單地發送消息,並且確保在收到傳送報告時T2已經結束? –

+0

消息通過第三方Web服務發送。 T2在發送消息之前無法執行,因爲消息會隨着發送結果而更新。 – makcro

回答

0

是的,我會將事務移動到服務級別,但我會重新考慮整個設計,看看是否可以將整個過程整合到一個線程中。如果我沒有記錯,Spring的事務管理是基於線程的 - 我懷疑你將能夠擁有一個跨越線程的事務。

另外,如果可能的話,嘗試簡化一些事情,以便只打一次數據庫。 如果您確實需要四次單獨更新,請在同一個線程的同一事務中按順序運行它們。否則,你將不會有一段很好的時間來嘗試讓交易生效。

顯式鎖定也要求一個受到傷害的世界 - 你很可能會因爲死鎖而結束這樣的事情。

編輯:針對OP的評論:

我建議尋找一種方法來分離從T2更新T3更新,讓T2事務提交做T3更新之前。

也許把傳遞報告放在消息隊列中。 然後提出一個策略,在T3中找到該項目並在存在的情況下進行更新,或者如果它不存在,則在稍後再嘗試。

如果您知道收到送達報告和結束T2事務之間存在最短或平均時間量,也許可以在處理遞送收據時創建此延遲量以創建T3更新。

+0

不幸的是,我不能避免多線程,因爲傳遞報告是通過HTTP接收的。我對事務隔離這個主題做了一些研究,並且認爲RDMS負責事務處理而不是春天。但是我想知道如果我爲T2和T3設置了可序列化的隔離會發生什麼? T2會獲得表上的鎖定,當t3嘗試做同樣的事情時,它是否會等待鎖定釋放,否則會失敗並拋出異常? – makcro