一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Hibernate鎖機(jī)制 悲觀鎖和樂觀鎖

 kakaxi 2011-07-21

Hibernate鎖機(jī)制 悲觀鎖和樂觀鎖

分類: Hibernate 141人閱讀 評論(1) 收藏 舉報(bào)

1、Pessimistic Locking 悲觀鎖;

     pessimistic [,pesi'mistik] adj. 悲觀的,厭世的;悲觀主義的

2、Optimistic   Locking 樂觀鎖;

     optimistic   [,?pti'mistik]    adj. 樂觀的;樂觀主義的

一、

hibernate鎖機(jī)制


1.悲觀鎖


它指的是對數(shù)據(jù)被外界修改持保守態(tài)度。假定任何時(shí)刻存取數(shù)據(jù)時(shí),都可能有另一個(gè)客戶也正在存取同一筆數(shù)據(jù),為了保持?jǐn)?shù)據(jù)被操作的一致性,于是對數(shù)據(jù)采取了數(shù)據(jù)庫層次的鎖定狀態(tài),依靠數(shù)據(jù)庫提供的鎖機(jī)制來實(shí)現(xiàn)。 
基于jdbc實(shí)現(xiàn)的數(shù)據(jù)庫加鎖如下: 
select * from account where name="Erica" for update 

在更新的過程中,數(shù)據(jù)庫處于加鎖狀態(tài),任何其他的針對本條數(shù)據(jù)的操作都將被延遲。本次事務(wù)提交后解鎖。 
而hibernate悲觀鎖的具體實(shí)現(xiàn)如下: 
String sql="查詢語句"; 
Query query=session.createQuery(sql); 
query.setLockMode("對象",LockModel.UPGRADE); 

說到這里,就提到了hibernate的加鎖模式: 

LockMode.NONE:無鎖機(jī)制。 
LockMode.WRITE:Hibernate在Insert和Update記錄的時(shí)候會自動(dòng)獲取。 
LockMode.READ:Hibernate在讀取記錄的時(shí)候會自動(dòng)獲取。 

這三種加鎖模式是供hibernate內(nèi)部使用的,與數(shù)據(jù)庫加鎖無關(guān): 

LockMode.UPGRADE:利用數(shù)據(jù)庫的for update字句加鎖。 

在這里我們要注意的是:只有在查詢開始之前(也就是hiernate生成sql語句之前)加鎖,才會真正通過數(shù)據(jù)庫的鎖機(jī)制加鎖處理。否則,數(shù)據(jù)已經(jīng)通過不包含for updata子句的sql語句加載進(jìn)來,所謂的數(shù)據(jù)庫加鎖也就無從談起。 
但是,從系統(tǒng)的性能上來考慮,對于單機(jī)或小系統(tǒng)而言,這并不成問題,然而如果是在網(wǎng)絡(luò)上的系統(tǒng),同時(shí)間會有許多聯(lián)機(jī),假設(shè)有數(shù)以百計(jì)或上千甚至更多的并發(fā)訪問出現(xiàn),我們該怎么辦?如果等到數(shù)據(jù)庫解鎖我們再進(jìn)行下面的操作,我們浪費(fèi)的資源是多少?--這也就導(dǎo)致了樂觀鎖的產(chǎn)生。 

2.樂觀鎖 

樂觀鎖定(optimistic locking)則樂觀的認(rèn)為資料的存取很少發(fā)生同時(shí)存取的問題,因而不作數(shù)據(jù)庫層次上的鎖定,為了維護(hù)正確的數(shù)據(jù),樂觀鎖定采用應(yīng)用程序上的邏輯實(shí)現(xiàn)版本控制的方法。 

例如若有兩個(gè)客戶端,A客戶先讀取了賬戶余額100元,之后B客戶也讀取了賬戶余額100元的數(shù)據(jù),A客戶提取了50元,對數(shù)據(jù)庫作了變更,此時(shí)數(shù)據(jù)庫中的余額為50元,B客戶也要提取30元,根據(jù)其所取得的資料,100-30將為70余額,若此時(shí)再對數(shù)據(jù)庫進(jìn)行變更,最后的余額就會不正確。 

在不實(shí)行悲觀鎖定策略的情況下,數(shù)據(jù)不一致的情況一但發(fā)生,有幾個(gè)解決的方法,一種是先更新為主,一種是后更新的為主,比較復(fù)雜的就是檢查發(fā)生變動(dòng)的數(shù)據(jù)來實(shí)現(xiàn),或是檢查所有屬性來實(shí)現(xiàn)樂觀鎖定。 

Hibernate 中透過版本號檢查來實(shí)現(xiàn)后更新為主,這也是Hibernate所推薦的方式,在數(shù)據(jù)庫中加入一個(gè)VERSON欄記錄,在讀取數(shù)據(jù)時(shí)連同版本號一同讀取,并在更新數(shù)據(jù)時(shí)遞增版本號,然后比對版本號與數(shù)據(jù)庫中的版本號,如果大于數(shù)據(jù)庫中的版本號則予以更新,否則就回報(bào)錯(cuò)誤。 

以剛才的例子,A客戶讀取賬戶余額1000元,并連帶讀取版本號為5的話,B客戶此時(shí)也讀取賬號余額1000元,版本號也為5,A客戶在領(lǐng)款后賬戶余額為500,此時(shí)將版本號加1,版本號目前為6,而數(shù)據(jù)庫中版本號為5,所以予以更新,更新數(shù)據(jù)庫后,數(shù)據(jù)庫此時(shí)余額為500,版本號為6,B客戶領(lǐng)款后要變更數(shù)據(jù)庫,其版本號為5,但是數(shù)據(jù)庫的版本號為6,此時(shí)不予更新,B客戶數(shù)據(jù)重新讀取數(shù)據(jù)庫中新的數(shù)據(jù)并重新進(jìn)行業(yè)務(wù)流程才變更數(shù)據(jù)庫。 

以Hibernate實(shí)現(xiàn)版本號控制鎖定的話,我們的對象中增加一個(gè)version屬性,例如: 

  1. public class Account {   
  2. private int version;   
  3. ....   
  4. public void setVersion(int version) {   
  5. this.version = version;   
  6. }   
  7. public int getVersion() {   
  8. return version;   
  9. }   
  10. ....   
  11. }   

而在映像文件中,我們使用optimistic-lock屬性設(shè)定version控制,<id>屬性欄之后增加一個(gè)<version>標(biāo)簽,如下: 
  1. <hibernate-mapping>   
  2. <class name="onlyfun.caterpillar.Account" talble="ACCOUNT"   
  3. optimistic-lock="version">   
  4. <id...../>   
  5. <version name="version" column="VERSION"/>   
  6. ....   
  7. </class>   
  8. </hibernate-mapping>  
  

設(shè)定好版本控制之后,在上例中如果B 客戶試圖更新數(shù)據(jù),將會引發(fā)StableObjectStateException例外,我們可以捕捉這個(gè)例外,在處理中重新讀取數(shù)據(jù)庫中的數(shù)據(jù),同時(shí)將 B客戶目前的數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)秀出來,讓B客戶有機(jī)會比對不一致的數(shù)據(jù),以決定要變更的部份,或者您可以設(shè)計(jì)程式自動(dòng)讀取新的資料,并重復(fù)扣款業(yè)務(wù)流程,直到數(shù)據(jù)可以更新為止,這一切可以在背景執(zhí)行,而不用讓您的客戶知道。 

但是樂觀鎖也有不能解決的問題存在:上面已經(jīng)提到過樂觀鎖機(jī)制的實(shí)現(xiàn)往往基于系統(tǒng)中的數(shù)據(jù)存儲邏輯,在我們的系統(tǒng)中實(shí)現(xiàn),來自外部系統(tǒng)的用戶余額更新不受我們系統(tǒng)的控制,有可能造成非法數(shù)據(jù)被更新至數(shù)據(jù)庫。因此我們在做電子商務(wù)的時(shí)候,一定要小心的注意這項(xiàng)存在的問題,采用比較合理的邏輯驗(yàn)證,避免數(shù)據(jù)執(zhí)行錯(cuò)誤。 

也可以在使用Session的load()或是lock()時(shí)指定鎖定模式以進(jìn)行鎖定。 

如果數(shù)據(jù)庫不支持所指定的鎖定模式,Hibernate會選擇一個(gè)合適的鎖定替換,而不是丟出一個(gè)例外。

 

 

二、

 

樂觀鎖(Optimistic Locking) 
相對悲觀鎖而言,樂觀鎖機(jī)制采取了更加寬松的加鎖機(jī)制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機(jī)制實(shí)現(xiàn),以保證操作最大程度的獨(dú)占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。如一個(gè)金融系統(tǒng),當(dāng)某個(gè)操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進(jìn)行修改時(shí)(如更改用戶帳戶余額),如果采用悲觀鎖機(jī)制,也就意味著整個(gè)操作過程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作員中途去煮咖啡的時(shí)間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對幾百上千個(gè)并發(fā),這樣的情況將導(dǎo)致怎樣的后果。 

樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。樂觀鎖,大多是基于數(shù)據(jù)版本(Version)記錄機(jī)制實(shí)現(xiàn)。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案,一般是通過為數(shù)據(jù)庫表增加一個(gè)“version”字段來實(shí)現(xiàn)。讀取出數(shù)據(jù)時(shí),將此版本號一同讀出,之后更新時(shí),對此版本號加一。此時(shí),將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。 

對于上面修改用戶帳戶信息的例子而言,假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個(gè)version字段,當(dāng)前值為1;而當(dāng)前帳戶余額字段(balance)為$100。 

1. 操作員A 此時(shí)將其讀出(version=1),并從其帳戶余額中扣除$50($100-$50)。 
2. 在操作員A操作的過程中,操作員B也讀入此用戶信息(version=1),并從其帳戶余額中扣除$20($100-$20)。 
3. 操作員A完成了修改工作,將數(shù)據(jù)版本號加一(version=2),連同帳戶扣除后余額(balance=$50),提交至數(shù)據(jù)庫更新,此時(shí)由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當(dāng)前版本,數(shù)據(jù)被更新,數(shù)據(jù)庫記錄version更新為2。 
4. 操作員B完成了操作,也將版本號加一(version=2)試圖向數(shù)據(jù)庫提交數(shù) 
據(jù)(balance=$80),但此時(shí)比對數(shù)據(jù)庫記錄版本時(shí)發(fā)現(xiàn),操作員B提交的數(shù)據(jù)版本號為2,數(shù)據(jù)庫記錄當(dāng)前版本也為2,不滿足“提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新“的樂觀鎖策略,因此,操作員B 的提交被駁回。這樣,就避免了操作員B 用基于version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A的操作結(jié)果的可能。 

從上面的例子可以看出,樂觀鎖機(jī)制避免了長事務(wù)中的數(shù)據(jù)庫加鎖開銷(操作員A和操作員B操作過程中,都沒有對數(shù)據(jù)庫數(shù)據(jù)加鎖),大大提升了大并發(fā)量下的系統(tǒng)整體性能表現(xiàn)。需要注意的是,樂觀鎖機(jī)制往往基于系統(tǒng)中的數(shù)據(jù)存儲邏輯,因此也具備一定的局限性,如在上例中,由于樂觀鎖機(jī)制是在我們的系統(tǒng)中實(shí)現(xiàn),來自外部系統(tǒng)的用戶余額更新操作不受我們系統(tǒng)的控制,因此可能會造成臟數(shù)據(jù)被更新到數(shù)據(jù)庫中。在系統(tǒng)設(shè)計(jì)階段,我們應(yīng)該充分考慮到這些情況出現(xiàn)的可能性,并進(jìn)行相應(yīng)調(diào)整(如將樂觀鎖策略在數(shù)據(jù)庫存儲過程中實(shí)現(xiàn),對外只開放基于此存儲過程的數(shù)據(jù)更新途徑,而不是將數(shù)據(jù)庫表直接對外公開)。Hibernate 在其數(shù)據(jù)訪問引擎中內(nèi)置了樂觀鎖實(shí)現(xiàn)。如果不用考慮外部系統(tǒng)對數(shù)據(jù)庫的更新操作,利用Hibernate提供的透明化樂觀鎖實(shí)現(xiàn),將大大提升我們的生產(chǎn)力。 
Hibernate中可以通過class描述符的optimistic-lock屬性結(jié)合version 
描述符指定。 

現(xiàn)在,我們?yōu)槭纠械腡User加上樂觀鎖機(jī)制。 
1. 首先為TUser的class描述符添加optimistic-lock屬性:


optimistic-lock屬性有如下可選取值:

  • none 無樂觀鎖
  • version 通過版本機(jī)制實(shí)現(xiàn)樂觀鎖
  • dirty 通過檢查發(fā)生變動(dòng)過的屬性實(shí)現(xiàn)樂觀鎖
  • all 通過檢查所有屬性實(shí)現(xiàn)樂觀鎖

其中通過version實(shí)現(xiàn)的樂觀鎖機(jī)制是Hibernate官方推薦的樂觀鎖實(shí)現(xiàn),同時(shí)也是Hibernate中,目前唯一在數(shù)據(jù)對象脫離Session發(fā)生修改的情況下依然有效的鎖機(jī)制。因此,一般情況下,我們都選擇version方式作為Hibernate樂觀鎖實(shí)現(xiàn)機(jī)制。 

2. 添加一個(gè)Version屬性描述符

 


注意version 節(jié)點(diǎn)必須出現(xiàn)在ID 節(jié)點(diǎn)之后。這里我們聲明了一個(gè)version屬性,用于存放用戶的版本信息,保存在TUser表的version字段中。 
此時(shí)如果我們嘗試編寫一段代碼,更新TUser表中記錄數(shù)據(jù),如:

 

 

  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();  

每次對TUser進(jìn)行更新的時(shí)候,我們可以發(fā)現(xiàn),數(shù)據(jù)庫中的version都在遞增。而如果我們嘗試在tx.commit 之前,啟動(dòng)另外一個(gè)Session,對名為Erica 的用戶進(jìn)行操作,以模擬并發(fā)更新時(shí)的情形:

 

 

  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();  
  9. TUser user =(TUser)userList.get(0);  
  10. TUser user2 =(TUser)userList2.get(0);  
  11. Transaction tx = session.beginTransaction();  
  12. Transaction tx2 = session2.beginTransaction();  
  13. user2.setUserType(99);  
  14. tx2.commit();  
  15. user.setUserType(1);  
  16. tx.commit();  

執(zhí)行以上代碼,代碼將在tx.commit()處拋出StaleObjectStateException異 
常,并指出版本檢查失敗,當(dāng)前事務(wù)正在試圖提交一個(gè)過期數(shù)據(jù)。通過捕捉這個(gè)異常,我 
們就可以在樂觀鎖校驗(yàn)失敗時(shí)進(jìn)行相應(yīng)處理。

 

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日韩国产精品激情一区| 亚洲男女性生活免费视频| 欧美在线视频一区观看| 国产性色精品福利在线观看| 日韩18一区二区三区| 亚洲天堂国产精品久久精品| 日本大学生精油按摩在线观看| 精品高清美女精品国产区| 亚洲精品欧美精品一区三区| 久久99亚洲小姐精品综合| 在线懂色一区二区三区精品| 亚洲国产中文字幕在线观看| 亚洲精品偷拍视频免费观看| 国语久精品在视频在线观看| 欧美精品亚洲精品日韩专区| 加勒比东京热拍拍一区二区| 国产亚洲神马午夜福利| 女人精品内射国产99| 亚洲国产精品久久琪琪| 日韩中文字幕在线不卡一区| 欧美日韩亚洲巨色人妻| 国产视频在线一区二区| 好吊色免费在线观看视频| 正在播放国产又粗又长| 欧美熟妇一区二区在线| 亚洲熟女国产熟女二区三区| 欧美日韩亚洲巨色人妻| 久久综合日韩精品免费观看| 婷婷色香五月综合激激情| 九九热在线免费在线观看| 亚洲一区二区久久观看| 精品久久久一区二区三| 久久天堂夜夜一本婷婷| 男人大臿蕉香蕉大视频| 激情亚洲一区国产精品久久| 99久久国产精品免费| 国产欧美一区二区久久| 欧美日韩欧美国产另类| 偷自拍亚洲欧美一区二页| 成人综合网视频在线观看| 人人妻在人人看人人澡|