乐观锁理解
相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。悲觀鎖大多數情況下依靠數據庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是數據庫 性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。
編輯本段樂觀鎖介紹
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。悲觀鎖大多數情況下依靠數據庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。而樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數據版本( Version )記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個 “version” 字段來實現。讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。編輯本段示例
如一個金融系統,當某個操作員讀取用戶的數據,并在讀出的用戶數據的基礎上進行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過 程中(從操作員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操作 員中途去煮咖啡的時間),數據庫記錄始終處于加鎖狀態,可以想見,如果面對幾百上千個并發,這樣的情況將導致怎樣的后果。 樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數據版本 ( Version )記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個 “version” 字段來實現。 讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。 對于上面修改用戶帳戶信息的例子而言,假設數據庫中帳戶信息表中有一個 version 字段,當前值為 1 ;而當前帳戶余額字段( balance )為 $100 。 1 操作員 A 此時將其讀出( version=1 ),并從其帳戶余額中扣除 $50( $100-$50 )。 2 在操作員 A 操作的過程中,操作員B 也讀入此用戶信息( version=1 ),并從其帳戶余額中扣除 $20 ( $100-$20 )。 3 操作員 A 完成了修改工作,將數據版本號加一( version=2 ),連同帳戶扣除后余額( balance=$50 ),提交至數據庫更新,此時由于提交數據版本大于數據庫記錄當前版本,數據被更新,數據庫記錄 version 更新為 2 。 4 操作員 B 完成了操作,也將版本號加一( version=2 )試圖向數據庫提交數據( balance=$80 ),但此時比對數據庫記錄版本時發現,操作員 B 提交的數據版本號為 2 ,數據庫記錄當前版本也為 2 ,不滿足 “ 提交版本必須大于記錄當前版本才能執行更新 “ 的樂觀鎖策略,因此,操作員 B 的提交被駁回。 這樣,就避免了操作員 B 用基于 version=1 的舊數據修改的結果覆蓋操作員A 的操作結果的可能。編輯本段優點
從上面的例子可以看出,樂觀鎖機制避免了長事務中的數據庫加鎖開銷(操作員 A和操作員 B 操作過程中,都沒有對數據庫數據加鎖),大大提升了大并發量下的系統整體性能表現。編輯本段缺點
需要注意的是,樂觀鎖機制往往基于系統中的數據存儲邏輯,因此也具備一定的局限性,如在上例中,由于樂觀鎖機制是在我們的系統中實現,來自外部系統的用戶余額更新操作不受我們系統的控制,因此可能會造成臟數據被更新到數據庫中。在系統設計階段,我們應該充分考慮到這些情況出現的可能性,并進行相應調整(如將樂觀鎖策略在數據庫存儲過程中實現,對外只開放基于此存儲過程的數據更新途徑,而不是將數據庫表直接對外公開)。編輯本段實現
Hibernate 在其數據訪問引擎中內置了樂觀鎖實現。如果不用考慮外部系統對數據庫的更新操作,利用 Hibernate 提供的透明化樂觀鎖實現,將大大提升我們的生產力。 Hibernate 中可以通過 class 描述符的 optimistic-lock 屬性結合 version 描述符指定。 現在,我們為之前示例中的 TUser 加上樂觀鎖機制。添加屬性
首先為 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> optimistic-lock 屬性有如下可選取值: Ø none 無樂觀鎖 Ø version 通過版本機制實現樂觀鎖 Ø dirty 通過檢查發生變動過的屬性實現樂觀鎖 Ø all 通過檢查所有屬性實現樂觀鎖 其中通過 version 實現的樂觀鎖機制是 Hibernate 官方推薦的樂觀鎖實現,同時也 是 Hibernate 中,目前唯一在數據對象脫離 Session 發生修改的情況下依然有效的鎖機 制。因此,一般情況下,我們都選擇 version 方式作為 Hibernate 樂觀鎖實現機制。添加描述符
添加一個 Version 屬性描述符 <hibernate-mapping> <class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true" optimistic-lock="version" > <id name="id" column="id" type="java.lang.Integer" > <generator class="native"> </generator> </id> <version column="version" name="version" type="java.lang.Integer" /> …… </class> </hibernate-mapping> 注意 version 節點必須出現在 ID 節點之后。 這里我們聲明了一個 version 屬性,用于存放用戶的版本信息,保存在 TUser 表的version 字段中。 此時如果我們嘗試編寫一段代碼,更新 TUser 表中記錄數據,如: Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica")); List userList = criteria.list(); TUser user =(TUser)userList.get(0); Transaction tx = session.beginTransaction(); user.setUserType(1); // 更新 UserType 字段 tx.commit(); 每次對 TUser 進行更新的時候,我們可以發現,數據庫中的 version 都在遞增。而如果我們嘗試在 tx.commit 之前,啟動另外一個 Session ,對名為 Erica 的用戶進行操作,以模擬并發更新時的情形: Session session= getSession(); Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica")); Session session2 = getSession(); Criteria criteria2 = session2.createCriteria(TUser.class); criteria2.add(Expression.eq("name","Erica")); List userList = criteria.list(); List userList2 = criteria2.list();TUser user =(TUser)userList.get(0); TUser user2 =(TUser)userList2.get(0); Transaction tx = session.beginTransaction(); Transaction tx2 = session2.beginTransaction(); user2.setUserType(99); tx2.commit(); user.setUserType(1); tx.commit(); 執行以上代碼,代碼將在 tx.commit() 處拋出 StaleObjectStateException 異常,并指出版本檢查失敗,當前事務正在試圖提交一個過期數據。通過捕捉這個異常,我們就可以在樂觀鎖校驗失敗時進行相應處理。 參考,http://baike.baidu.com/view/1953089.htm(效果更好) 推薦文章:http://ifeve.com/reentrantlock-and-fairness/轉載于:https://www.cnblogs.com/langtianya/archive/2013/04/13/3018536.html
總結
- 上一篇: 做脑部造影要打麻药吗
- 下一篇: 酒量不好的人喝一瓶黑方会怎么样,特别是我