2014-04-30 21 views
1

我有兩個服務器(後臺和前臺)運行數據庫的連接模塊。它與相同的數據庫連接。Hibernate中的併發事務

我使用JPA(Hibernate實現)和Spring事務管理。

我有以下問題:

我不得不從表A與MAX值+兩個不同字段的1(FIELDA從表A,fieldB從tableB的)更新FIELDA

情況1:

更新之前

TABLEA 爲fA = 100

tableB的 fB的 = 102

後更新

TABLEA 爲fA = 103

tableB的 fB的 = 102


情況2:

更新之前

TABLEA 爲fA = 102

tableB的 fB的 = 100

後更新

TABLEA 爲fA = 103

tableB的 fB的 = 100

與此代碼的方法是事務性的和前做的事情(如創建實體)之後。所以之前提交事務,如果其他應用程序試圖獲得的價值,這將是過時的,它會保存在FIELDA相同的值。休眠會話與分佈式系統不同。

我不能使用數據庫序列(法律問題,因爲它是關於發票)或分佈式緩存對Hibernate(系統問題)

我怎樣才能做到這一點?

謝謝

回答

2

你可以使用鎖定。適當的加鎖類型取決於你的用例。

如果併發更新的概率很低,請使用樂觀鎖定。如果發生更新衝突,請捕獲Exception,刷新實體,重新應用更改並重試提交。

如果您使用樂觀鎖定,建議您將@Version字段添加到您的實體。不保證版本字段的樂觀鎖定不受支持。

如果併發修改的概率很高,請使用悲觀鎖定。因此,您可以序列化行上的寫入。請注意,這種類型的鎖定可能會造成瓶頸,因爲事務在獲取鎖定之前排隊等待更新和其他事務超時。

爲了儘量減少lokc時間,您可以在一個單獨的查詢應用鎖:

query.setLockMode(LockMode.WRITE) 

編輯:鎖可大概在分佈式環境中使用安全。

樂觀鎖定是在提交時(或等價)檢查數據庫中的@Version字段 - 使用讀提交的隔離(默認),不存在丟失對實體的已提交更改的風險。

悲觀鎖定在DB級別上實現,通常使用SELECT FOR UPDATE或類似的。所以你不必擔心。

+0

感謝@ kostja,休眠鎖集羣安全嗎?(我有兩臺服務器共享相同的數據庫) –

+1

不客氣:)是的,鎖是兩個羣集安全:請參閱編輯。 – kostja

+1

Wheer或多或少會遇到競爭狀況是錯誤的問題。正確的問題是:哇你的代碼(或用戶!)能夠解決衝突。如果您可以發出一條錯誤消息,告訴用戶再次嘗試,請使用樂觀鎖定。純程序化和可靠地完成同樣的事情非常困難。捕捉異常只是一個複雜的算法的入口點。這就是爲什麼我認爲崇高的鎖定是解決這個問題的唯一簡單方法。 – BetaRide

1

您需要pesimistic鎖定。通過Hibernate,您可以在JDBC或事務級別上執行此操作。

閱讀hibernate手冊中的chapter about locking

+0

你不需要**悲觀鎖定在這裏。請考慮在鏈接背後提供相關信息併發布。 – kostja

+0

這是非常不可能的(每月一個或兩個案例,10.000) –

0

我不知道如果我理解正確你的問題,但也許在你的DAO可以準備一個方法,其中你可以做這個

DetachedCriteria dc = DetachedCriteria.forClass(ClassA); 
dc.setProjection(Projections.max("id")); 
logger.info(svc.getMax(dc)); 

一旦你得到了最大值可以更新其他表

Angelo