1. 程式人生 > >hibernate 樂觀鎖與悲觀鎖的實現

hibernate 樂觀鎖與悲觀鎖的實現

Hibernate支援兩種鎖機制:
即通常所說的“悲觀鎖(Pessimistic Locking)”和 “樂觀鎖(OptimisticLocking)”。

悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改資料)。

Hibernate的加鎖模式有:
Ø LockMode.NONE : 無鎖機制。
Ø LockMode.WRITE :Hibernate在Insert和Update記錄的時候會自動
獲取。
Ø LockMode.READ : Hibernate在讀取記錄的時候會自動獲取。
以上這三種鎖機制一般由Hibernate內部使用,如Hibernate為了保證Update
過程中物件不會被外界修改,會在save方法實現中自動為目標物件加上WRITE鎖。
Ø LockMode.UPGRADE :利用資料庫的for update子句加鎖。
Ø LockMode. UPGRADE_NOWAIT :Oracle的特定實現,利用Oracle的for update nowait子句實現加鎖。 

 Hibernate的悲觀鎖,也是基於資料庫的鎖機制實現。 下面的程式碼實現了對查詢記錄的加鎖:1
String hqlStr  = " from TUser as user where user.name=’Erica’ "
2 Query query =  session.createQuery(hqlStr); 
3 query.setLockMode(" user " ,LockMode.UPGRADE);  // 加鎖  4 List userList  =  query.list(); // 執行查詢,

獲取資料 query.setLockMode 對查詢語句中特定別名所對應的記錄進行加鎖(我們為 TUser類指定了一個別名“user”),這裡也就是對返回的所有user記錄進行加鎖。 觀察執行期Hibernate生成的SQL語句: 

1 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子句實現了悲觀鎖機制。

上面這兩種鎖機制是我們在應用層較為常用的,加鎖一般通過以下方法實現:
Criteria.setLockMode
Query.setLockMode
Session.lock
注意,只有在查詢開始之前(也就是Hiberate 生成SQL 之前)設定加鎖,才會 真正通過資料庫的鎖機制進行加鎖處理,否則,資料已經通過不包含for update 子句的Select SQL載入進來,所謂資料庫加鎖也就無從談起。






樂觀鎖,大多是基於資料版本(Version)記錄機制實現。何謂資料版本?即為資料增加一個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加一個“version”欄位來實現。讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對,如果提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。

1. 首先為TUser的class描述符新增optimistic-lock屬性:< hibernate- mapping >  
< class  
name
= " org.hibernate.sample.TUser "  
table
= " t_user "  
dynamic
- update = " true"  
dynamic
- insert = " true"  
optimistic
- lock = " version"  
>  
…… 
</ class >  
</ hibernate- mapping >  新增一個Version屬性描述符
程式碼內容
 1 < hibernate- mapping >  2 < class 3 name= " org.hibernate.sample.TUser "  4 table= " t_user "  5 dynamic- update = " true"  6 dynamic- insert = " true"  7 optimistic- lock = " version"  8 >  9 < id  
10 name= " id " 11 column= " id " 12 type= " java.lang.Integer " 13 > 14 < generator class = " native "> 15 </ generator> 16 </ id> 17 < version  
18 column= " version " 19 name= " version " 20 type= " java.lang.Integer " 21 /> 22 ……  
23 </ class> 24 </ hibernate- mapping > 25

注意version 節點必須出現在ID 節點之後。
 這裡我們聲明瞭一個version屬性,用於存放使用者的版本資訊,儲存在TUser表的 version欄位中。 此時如果我們嘗試編寫一段程式碼,更新TUser表中記錄資料,如:
程式碼內容

1 Criteria criteria  =  session.createCriteria(TUser. class );  
2 criteria.add(Expression.eq(" name " , "Erica " ));  
3 List userList =  criteria.list();  
4 TUser user = (TUser)userList.get(0 );  
5 Transaction tx =  session.beginTransaction();  
6 user.setUserType(1 );  // 更新UserType欄位   7 tx.commit();  
8

每次對TUser進行更新的時候,我們可以發現,資料庫中的version都在遞增。 而如果我們嘗試在tx.commit 之前,啟動另外一個Session,對名為Erica 的用 戶進行操作,以模擬併發更新時的情形:
程式碼內容

 1 Session session = getSession();  
 2 Criteria criteria =  session.createCriteria(TUser.class );  
 3 criteria.add(Expression.eq(" name " , "Erica " ));  
 4 Session session2 =  getSession();  
 5 Criteria criteria2 =  session2.createCriteria(TUser.class );  
 6 criteria2.add(Expression.eq(" name " , "Erica " ));  
 7 List userList =  criteria.list();  
 8 List userList2 =  criteria2.list();TUser user = (TUser)userList.get(0 );  
 9 TUser user2 = (TUser)userList2.get(0 );  
10 Transaction tx =  session.beginTransaction();  
11 Transaction tx2 =  session2.beginTransaction();  
12 user2.setUserType(99 );  
13 tx2.commit();  
14 user.setUserType(1 );  
15 tx.commit();  
16

執行以上程式碼,程式碼將在tx.commit()處丟擲StaleObjectStateException異 常,並指出版本檢查失敗,當前事務正在試圖提交一個過期資料。通過捕捉這個異常,我 們就可以在樂觀鎖校驗失敗時進行相應處理。 




悲觀鎖與樂觀鎖的比較:
悲觀鎖大多數情況下依靠資料庫的鎖機制實現,以保證操作最大程度的獨佔性。但隨之而來的就是資料庫效能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受;
相對悲觀鎖而言,樂觀鎖機制採取了更加寬鬆的加鎖機制。樂觀鎖機制往往基於系統中的資料儲存邏輯,因此也具備一定的侷限性,如在上例中,由於樂觀鎖機制是在我們的系統中實現,來自外部系統的更新操作不受我們系統的控制,因此可能會造成髒資料被更新到資料庫中。在
系統設計階段,我們應該充分考慮到這些情況出現的可能性,並進行相應調整(如將樂觀鎖策略在資料庫儲存過程中實現,對外只開放基於此儲存過程的資料更新途徑,而不是將資料庫表直接對外公開)。
Hibernate 在其資料訪問引擎中內建了樂觀鎖實現。如果不用考慮外部系統對資料庫的更新操作,利用Hibernate提供的透明化樂觀鎖實現,將大大提升我們的生產力。
Hibernate中可以通過class描述符的optimistic-lock屬性結合version描述符指定。
optimistic-lock屬性有如下可選取值:
Ø none
無樂觀鎖
Ø version
通過版本機制實現樂觀鎖
Ø dirty
通過檢查發生變動過的屬性實現樂觀鎖
Ø all
通過檢查所有屬性實現樂觀鎖

其中通過version實現的樂觀鎖機制是Hibernate官方推薦的樂觀鎖實現,同時也是Hibernate中,目前唯一在資料物件脫離Session發生修改的情況下依然有效的鎖機制。因此,一般情況下,我們都選擇version方式作為Hibernate樂觀鎖實現機制。

相關推薦

hibernate 樂觀悲觀實現

Hibernate支援兩種鎖機制: 即通常所說的“悲觀鎖(Pessimistic Locking)”和 “樂觀鎖(OptimisticLocking)”。 悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實

Java並發問題--樂觀悲觀以及樂觀的一種實現方式-CAS

RF -- 指針 locking water 更多 錯誤 創建 判斷 首先介紹一些樂觀鎖與悲觀鎖: 悲觀鎖:總是假設最壞的情況,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖。傳統的關系型數據庫裏邊就用到了很多這

最通俗易懂的樂觀悲觀原理及實現

一、樂觀鎖   總是認為不會產生併發問題,每次去取資料的時候總認為不會有其他執行緒對資料進行修改,因此不會上鎖,但是在更新時會判斷其他執行緒在這之前有沒有對資料進行修改,一般會使用版本號機制或CAS操作實現。  version方式:一般是在資料表中加上一個資料版本號ver

【轉】Java併發問題--樂觀悲觀以及樂觀的一種實現方式-CAS

首先介紹一些樂觀鎖與悲觀鎖: 悲觀鎖:總是假設最壞的情況,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻塞直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上

Java併發問題--樂觀悲觀以及樂觀的一種實現方式-CAS

首先介紹一些樂觀鎖與悲觀鎖:   悲觀鎖:總是假設最壞的情況,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻塞直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

樂觀悲觀

到你 目前 from 提高 選中 base 排它鎖 之前 準備 在多用戶環境中,在同一時間可能會有多個用戶更新相同的記錄,這會產生沖突。這就是著名的並發性問題。 典型的沖突有: l 丟失更新:一個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如:用戶A把值從6改

樂觀悲觀的簡單區分

個數 行數 但是 分布式系 修改 讀寫 使用場景 狀態 控制 1、鎖的出現,是因為並發讀寫同一個數據的時候,需要進行數據完備性的保護,避免臟讀、臟寫等。 2、樂觀鎖,需要在事務中加鎖,在讀取數據的時候,不必在意數據是否已經被修改了(即允許臟讀);但是在寫入數據的時候,要檢查

[數據庫事務]詳解七: 深入理解樂觀悲觀

ood insert 影響 hiberna memcach begin 策略 goods 其它 註明: 本文轉載自http://www.hollischuang.com/archives/934在數據庫的鎖機制中介紹過,數據庫管理系統(DBMS)中的並發控制的任務是確保在

mysql的樂觀悲觀

想要 附加 情況 屬性 ... str 但是 share 版本 樂觀鎖 總是認為不會產生並發問題,每次去取數據的時候總認為不會有其他線程對數據進行修改,因此不會上鎖,但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS操作實現。 例如: 有這

深入理解樂觀悲觀

遇到 實現 個數 默認 ODB date 開始 安全 行數 前言在數據庫的鎖機制中介紹過,數據庫管理系統(DBMS)中的並發控制的任務是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和統一性以及數據庫的統一性。 樂觀並發控制(樂觀鎖)和悲觀並發控制(悲觀鎖)是並

Java多線程系列---“基礎篇”13之 樂觀悲觀

而是 關系型 lock color 情況 發現 mis 再次 中一 轉自:http://www.cnblogs.com/zhengbin/p/5657435.html 樂觀鎖   樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認

資料庫中的樂觀悲觀

樂觀鎖: 在關係資料庫管理系統裡,樂觀併發控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種併發控制的方法。它假設多使用者併發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分資料。在提交資料更新之前,

資料庫 樂觀悲觀

樂觀鎖 總是認為不會產生併發問題,每次去取資料的時候總認為不會有其他執行緒對資料進行修改,因此不會上鎖,但是在更新時會判斷其他執行緒在這之前有沒有對資料進行修改,一般會使用版本號機制或CAS操作實現。 version方式:一般是在資料表中加上一個資料版本號version欄位,表示資料被修改的次數,當

什麼是樂觀悲觀

樂觀鎖: 簡單的來說:就是認為別人不會過來修改它的資料,常見的樂觀鎖通常會帶一個version(版本),等到提交的時候,會去檢查一下版本,如果版本修改了,就會丟擲異常,並且回滾資料; 樂觀鎖通常需要在表中額外設計一個version的冗餘欄位 並且在插入資料的時候,將version初始

關於樂觀悲觀的實際應用

開門見山,先聊一聊我實際遇到的業務問題: 在專案中有一個競猜下注的功能,它的賠率是根據A隊和B隊兩邊的下注總金額來計算的。於是當有使用者下注某一邊時,兩邊的賠率都會進行相應的變化。 反應到資料庫裡就是(簡化版本),一個人下注,會更改資料庫盤口表的幾個欄位:A隊賠率,A隊下注金額、B隊賠率,B隊下注金額

深入Mysql機制(四)樂觀悲觀

深入Mysql鎖機制(四)樂觀鎖與悲觀鎖 在資料庫鎖機制中介紹過,資料庫管理系統(DBMS)中的併發控制的任務是確保在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性。 樂觀併發控制(樂觀鎖)和悲觀併發控制(悲觀鎖)是併發控制主要採用的技術手段。

Java併發問題--樂觀悲觀

首先為什麼需要鎖(併發控制)? 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。 典型的衝突有: 丟失更新:一個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如:使用者A把值從6改為2,使用者B把值從2改為

關於樂觀悲觀的應用解決方案

原文連結 https://juejin.im/post/5c0009adf265da614a3a3741 在專案中有一個競猜下注的功能,它的賠率是根據A隊和B隊兩邊的下注總金額來計算的。於是當有使用者下注某一邊時,兩邊的賠率都會進行相應的變化。 反應到資料庫裡就是(簡化版本),一個

樂觀悲觀及應用舉例

最近因為在工作中需要,學習了樂觀鎖與悲觀鎖的相關知識,這裡我通過這篇文章,把我自己對這兩個“鎖家”兄弟理解記錄下來;        - 悲觀鎖:正如其名,它指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)的修改持保守態度,因此,在整個資料處理過程

技術分享:關於樂觀悲觀的實際應用

    開門見山,先聊一聊我實際遇到的業務問題: 在專案中有一個競猜下注的功能,它的賠率是根據A隊和B隊兩邊的下注總金額來計算的。於是當有使用者下注某一邊時,兩邊的賠率都會進行相應的變化。 反應到資料庫裡就是(簡化版本),一個人下注,會更改資料庫盤口表的幾個