Hibernate數據丟失更新問題及解決


第一類丟失更新 

    A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。這種錯誤可能造成很嚴重的問題,通過下面的賬戶取款轉賬就可以看出來:

 

 

時間

取款事務A

轉賬事務B

T1

開始事務

 

T2

 

開始事務

T3

查詢賬戶余額為1000元    

 

T4

 

查詢賬戶余額為1000元

T5

 

匯入100元把余額改為1100元

T6

 

提交事務

T7

取出100元把余額改為900元

 

T8

撤銷事務

 

T9

余額恢復為1000 元(丟失更新)

 

   

 

 

A事務在撤銷時,“不小心”將B事務已經轉入賬戶的金額給抹去了。 

    第二類丟失更新 

A事務覆蓋B事務已經提交的數據,造成B事務所做操作丟失:   

時間

轉賬事務A

取款事務B

T1

 

開始事務

T2

開始事務

                         

T3

               

查詢賬戶余額為1000元    

T4

查詢賬戶余額為1000元

                         

T5

 

取出100元把余額改為900元

T6

 

提交事務           

T7

匯入100元

 

T8

提交事務

 

T9

把余額改為1100 元(丟失更新)

 

  

 

 

    上面的例子里由於支票轉賬事務覆蓋了取款事務對存款余額所做的更新,導致銀行最后損失了100元,相反如果轉賬事務先提交,那么用戶賬戶將損失100元

 

解決方法:有兩種

第一種:悲觀鎖(幾乎不用,因為效率及慢,影響用戶體驗) 

  一個典型的倚賴數據庫的悲觀鎖調用:

select * from account where name="Erica" for update

這條 sql 語句鎖定了 account 表中所有符合檢索條件( name="Erica" )的記錄。 本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。

Hibernate 的悲觀鎖,也是基於數據庫的鎖機制實現。

下面的代碼實現了對查詢記錄的加鎖:

String hqlStr = "from TUser as user where user.name='Erica'";

Query query = session.createQuery(hqlStr);

query.setLockMode("user",LockMode.UPGRADE); // 加鎖

List userList = query.list();// 執行查詢,獲取數據

query.setLockMode 對查詢語句中,特定別名所對應的記錄進行加鎖(我們為TUser 類指定了一個別名"user"),這里也就是對返回的所有 user 記錄進行加鎖。

觀察運行期 Hibernate 生成的 SQL 語句:

select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name='Erica' ) for update

這里 Hibernate 通過使用數據庫的 for update 子句實現了悲觀鎖機制。

第二種:樂觀鎖(建議用)

  1.在對應的JavaBean中添加一個屬性,名稱可以是任意的。例如:private Integer version; 提供get和set方法

  2.在映射的配置文件中,提供<version name="version"/>標簽即可。

  原理:在開啟一個事物之前,數據庫會自動為你添加一個version字段,默認值為0,當一個用戶完成了事物並且更新了數據后,數據庫會自動把version字段的值

改為1,同時,如果另外一個用戶也操作這條數據,那么,當他想保存數據的時候,就會出現版本不對的問題,從而修改失敗,必須重新修改。這樣一來,就可以避免

丟失更新的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM