2011-03-01 54 views
1

我有一個對象GeneralKnowledgeTest,它包含很多統計字段(ratingsCount,responsesCount,ratingStars ...),每更新一次用戶都會進行測試takeTest() - >事務性方法)。簡單的設計問題關於樂觀鎖定在spring/jpa/hibernate

這可能會發生,很多用戶正在以相同的時間相同的測試,所以我想實現一個樂觀鎖(@version)和重試takeTest方法情況下的樂觀鎖定異常被拋出AA攔截。

因此,在takeTest方法中,我總是得到一個新的GeneralKnowledgeTest實例, entityManager.find(testId),然後更新其統計字段。如果拋出一個樂觀的異常,攔截器將簡單地重試takeTest方法直到它成功。

您對此程序有什麼看法?對於可能有很多用戶試圖進行相同測試的系統,這是否是實現樂觀鎖定的好方法?

PS。業務不會承認顯示任何警告消息,以防樂觀鎖異常被拋出,因此攔截器是一個必須允許順利執行...

回答

0

我假設這些統計數據只在測試結束時更新並且測試需要合理的時間來運行,所以這將減少樂觀鎖定失敗的可能性。另外,用戶是否有可能以突發方式完成測試,例如,由於在特定時間開始測試?這會增加鎖定失敗的可能性。

如果吞吐量仍然可能會導致併發更新,那麼最好將聚合內存中的統計信息(以線程安全的方式)並定期將其寫入數據庫。

+0

許多用戶很可能在同一時間內完成測試(如當天測試等)。我已經讀過樂觀鎖定在性能方面沒問題,所以沒有數據庫鎖定。 (設想100個用戶在同一時間內完成相同的測試,同時考慮takeTest是一個複雜的方法,創建許多額外的數據庫對象,使交易花費更長時間)。但是一般來說,我認爲這有什麼不妥之處?是否有任何錯誤或缺點?預先感謝您 – 2011-03-01 21:02:04

+0

不,沒有錯誤。樂觀鎖定失敗將導致數據被重新讀取,但會增加數據庫負載,並且重做測試邏輯會增加CPU負載。這種方法沒有問題,只取決於您希望鎖定失敗的頻率。 – Will 2011-03-01 21:29:58

0

這聽起來像一個有效的方法:

休眠檢查對象實例的版本在沖洗時間,如果檢測到的併發修改拋出異常。這是由開發人員抓住並處理這個異常。常用選項是用戶合併更改或重新啓動與非陳舊數據的業務對話的機會。

你也可以看看將IsolationLevel設置爲SERIALIZED或鎖定表格行。

另一種選擇可能是將對象分開,使用調度程序等進入並重新附加(更新)統計信息來更新它。然而,這可能需要您的服務方法(更新統計信息)進行同步,並且由於此服務可能是代理服務器,我不認爲同步它是可能的。