在使用CMT的Java EE服務器上,我使用ehcache在業務對象層(EJB)和數據訪問層(使用JDBC的POJO)之間實現緩存層。我似乎遇到兩個線程在使用自動填充Ehcache時訪問相同記錄的競態條件。緩存被鎖定在記錄的主鍵上。Ehcache與數據庫不同步
的情況是:
- 第一個線程更新記錄在數據庫中,並從緩存中記錄(但數據庫提交不一定馬上發生 - 可能還有其他的查詢遵循。)
- 第二個線程讀取記錄,導致緩存重新填充。
- 第一個線程提交事務。
這一切都發生在幾分之一秒內。它導致緩存與數據庫不同步,並且隨後的記錄讀取操作將返回陳舊的緩存數據,直到執行另一個更新,或者該條目從緩存中過期。我可以在短時間內處理陳舊的數據(通常是一個事務的長度),但不是分鐘,這是我想要緩存對象的時間。
對於避免這種競賽條件的任何建議?
UPDATE:
清除後的交易已承諾肯定會是理想的高速緩存。問題是,在使用CMT的J2EE環境中,當緩存層夾在業務層(無狀態會話EJB)和數據訪問層之間時,如何執行此操作?
爲了清楚說明這種限制,有問題的方法調用可能會或可能不會與之前或之後發生的其他方法調用處於相同的事務中。我不能強制進行提交(或者在單獨的事務中執行此操作),因爲這會改變事務邊界與客戶端代碼的期望。任何後續的異常都不會回滾整個事務(在這種情況下非常規地清除緩存是可接受的副作用)。我無法控制進入交易的入口點,因爲它本質上是客戶可以使用的API。將清除緩存的可重複性推送到客戶端應用程序是不合理的。
我希望能夠延遲任何緩存清除操作,直到整個事務被EJB容器提交,但我沒有辦法掛鉤到那個邏輯中,並用無狀態會話bean運行我自己的代碼。
更新#2:
最有希望的解決方案,到目前爲止,短的重大設計變更的,就是用的Ehcache 2.0的JTA支持:http://ehcache.org/documentation/apis/jta
這意味着升級到了Ehcache 2。併爲數據庫啓用XA事務,這可能會產生負面影響。但它似乎是「正確」的方式。
當然這是理想的,但如何做到這一點?我已經更新了這個問題來澄清這些限制。 – 2012-05-08 19:41:14
@Chris我已經更新了答案,希望它有幫助。 – jmruc 2012-05-09 15:11:27
嗨Kril,SessionSynchronization接口僅適用於有狀態會話Bean ..如果它可用於無狀態,它肯定是一個很好的解決方案。 – 2012-05-10 18:09:04