<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-109  評論-187  文章-25  trackbacks-0

    文章轉自網上好像是玉米田的,忘記了

    鎖(
    locking
    業務邏輯的實現過程中,往往需要保證數據訪問的排他性。如在金融系統的日終結算
    處理中,我們希望針對某個 cut-off 時間點的數據進行處理,而不希望在結算進行過程中
    (可能是幾秒種,也可能是幾個小時),數據再發生變化。此時,我們就需要通過一些機
    制來保證這些數據在某個操作過程中不會被外界修改,這樣的機制,在這里,也就是所謂
    ,即給我們選定的目標數據上鎖,使其無法被其他程序修改。
    Hibernate
    支持兩種鎖機制:即通常所說的 悲觀鎖( Pessimistic Locking
    樂觀鎖( Optimistic Locking
    悲觀鎖( Pessimistic Locking
    悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自
    外部系統的事務處理)修改持保守態度,因此,在整個數據處理過程中,將數據處于鎖定
    狀態。悲觀鎖的實現,往往依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能
    真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系
    統不會修改數據)。
    一個典型的倚賴數據庫的悲觀鎖調用:
    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 子句實現了悲觀鎖機制。
    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
    子句實現加鎖。
    上面這兩種鎖機制是我們在應用層較為常用的,加鎖一般通過以下方法實現:
    Criteria.setLockMode
    Query.setLockMode
    Session.lock
    注意,只有在查詢開始之前(也就是 Hiberate 生成 SQL 之前)設定加鎖,才會
    真正通過數據庫的鎖機制進行加鎖處理,否則,數據已經通過不包含 for update
    子句的 Select SQL 加載進來,所謂數據庫加鎖也就無從談起。
    樂觀鎖( Optimistic Locking
    相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。悲觀鎖大多數情況下依
    靠數據庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是數據庫
    性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。
    如一個金融系統,當某個操作員讀取用戶的數據,并在讀出的用戶數據的基礎上進
    行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過
    程中(從操作員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操作
    員中途去煮咖啡的時間),數據庫記錄始終處于加鎖狀態,可以想見,如果面對幾

    百上千個并發,這樣的情況將導致怎樣的后果。
    樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數據版本
    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 加上樂觀鎖機制。

    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>
    optimistic-lock
    屬性有如下可選取值:
    ? none
    無樂觀鎖
    ? version
    通過版本機制實現樂觀鎖
    ? dirty
    通過檢查發生變動過的屬性實現樂觀鎖
    ? all
    通過檢查所有屬性實現樂觀鎖
    其中通過 version 實現的樂觀鎖機制是 Hibernate 官方推薦的樂觀鎖實現,同時也
    Hibernate 中,目前唯一在數據對象脫離 Session 發生修改的情況下依然有效的鎖機
    制。因此,一般情況下,我們都選擇 version 方式作為 Hibernate 樂觀鎖實現機制。
    2
    添加一個 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
    常,并指出版本檢查失敗,當前事務正在試圖提交一個過期數據。通過捕捉這個異常,我
    們就可以在樂觀鎖校驗失敗時進行相應處理

    ?

    posted on 2006-11-15 08:35 小小程序程序員混口飯吃 閱讀(51670) 評論(23)  編輯  收藏 所屬分類: java

    評論:
    # re: 樂觀鎖與悲觀鎖 2007-11-23 10:25 | 混混
    確實不錯  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2008-03-04 16:32 | 過客
    好東西  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2008-06-17 17:28 | aaa
    寫的不錯  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2009-01-08 14:23 | vvvvv
    這段內容來自《深入淺出Hibernate》一書(作者:夏昕 曹曉鋼 唐勇 2005年版)
    第5章 Hibernate 高級特性
    5.1.5 事務管理
    鎖(locking)

    作者寫得是很不錯,贊一個!  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2009-02-20 16:45 | guooo
    很好,
    第一次了解的這么清晰  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2011-01-19 22:43 | gavin
    有收獲.....  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2011-02-15 17:19 | JayGong
    oracle 有個多版本,查詢一致的概念 所以在你的“結算時的cut-off 時間點的數據” 在oracle中不會存在   回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2011-04-30 22:04 | test
    寫的不錯,挺深入的  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2012-08-13 09:41 | beiyeren
    寫的不錯,的確挺好,支持  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2012-12-13 11:12 | drac
    >>如將樂觀鎖策略在數據庫存儲過程中實現,對外只開放基于此存儲過程的數據>>更新途徑,而不是將數據庫表直接對外公開

    是不是樂觀鎖對比悲觀鎖的性能提升只是體現在數據的讀操作上?  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2013-03-04 23:47 | dd
    案發生法good  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2013-03-04 23:47 | dd
    good  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2013-03-31 12:39 | cl
    學習!  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2014-02-10 03:55 | Hua
    這是我看過介紹的最好的樂觀鎖和悲觀鎖的講解了,謝謝  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2014-04-17 16:30 | 1
    基本原則張無基本原則  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2014-04-17 16:31 | Cj
    不錯  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2014-05-07 02:26 |
    非常不錯  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2014-06-26 17:15 | Larry
    非常好的東西。相見恨晚。  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2014-07-19 18:38 | 小虎
    不錯啊,看的輕松,舉例不錯,讓人易懂  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2014-12-19 14:30 | i余數
    學習了  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2015-02-03 16:23 | 11
    學習了  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖 2015-07-01 17:32 | cpp
    你的例子沒有舉好,如果直接update 余額列名-扣除金額 就不會 出現你說的問題,update的時候 數據庫自動鎖表的哦,你的例子 應該舉 用戶 有一筆扣款記錄,扣50
    a管理員 和 b管理員同時先后更新這一筆處理的時候,適用于你的處理  回復  更多評論
      
    # re: 樂觀鎖與悲觀鎖[未登錄] 2016-01-25 08:33 | 過客
    寫的不錯!  回復  更多評論
      
    主站蜘蛛池模板: 亚洲gv白嫩小受在线观看| 亚洲国产欧美国产综合一区| 又大又硬又爽又粗又快的视频免费| 亚洲欧洲中文日产| 亚洲国产成人久久精品99| 久久99精品国产免费观看| 亚洲色大成网站www永久男同| 亚洲熟妇中文字幕五十中出| 国产精品1024永久免费视频| 一级毛片免费在线| 亚洲啪啪免费视频| 久久亚洲高清综合| 亚洲欧洲中文日韩av乱码| 无码一区二区三区免费| 国产精品亚洲一区二区无码| 亚洲精品美女久久久久| 内射无码专区久久亚洲| 免费在线观看h片| 三年片免费高清版| 亚洲成av人片天堂网无码】| 亚洲免费视频在线观看| 亚洲国产精品一区二区九九| 4hu四虎最新免费地址| 99久久成人国产精品免费| 亚洲av日韩aⅴ无码色老头| 亚洲视频精品在线| 亚洲色欲久久久综合网东京热| 青青草免费在线视频| 久久国产精品免费专区| 亚洲视频在线一区| 久久久久亚洲av毛片大| 日本一区二区三区日本免费| 99在线精品免费视频九九视| 国产偷伦视频免费观看| jizz免费在线观看| 污网站免费在线观看| 色天使色婷婷在线影院亚洲| 亚洲中文字幕无码av在线| 97久久精品亚洲中文字幕无码| 思思re热免费精品视频66 | sss日本免费完整版在线观看|