Hibernate入門 29 - 樂觀鎖定

入門 29 - 樂觀鎖定 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 悲觀鎖定假定任何時刻存取數據時,都可能有另一個客戶也正在存取同一筆數據,因而對數據採取了數據庫層次的鎖定狀態,在鎖定的時間內其它的客戶不能對資 料進行存取,對於單機或小系統而言,這並不成問題,然而如果是在網絡上的系統,同時間會有許多聯機,如果每一次讀取數據都造成鎖定,其後繼的存取就必須等待,這將造成效能上的問題,造成後繼使用者的長時間等待。
 樂觀鎖定(optimistic locking)則樂觀的認爲資料的存取很少發生同時存取的問題,因而不作數據庫層次上的鎖定,爲了維護正確的數據,樂觀鎖定使用應用程序上的邏輯實現版本控制的解決。
 例如若有兩個客戶端,A客戶先讀取了賬戶餘額1000元,之後B客戶也讀取了賬戶餘額1000元的數據,A客戶提取了500元,對數據庫作了變更,此時 數據庫中的餘額爲500元,B客戶也要提取300元,根據其所取得的資料,1000-300將爲700餘額,若此時再對數據庫進行變更,最後的餘額就會不正確。
 在不實行悲觀鎖定策略的情況下,數據不一致的情況一但發生,有幾個解決的方法,一種是先更新爲主,一種是後更新的爲主,比較複雜的就是檢查發生變動的數據來實現,或是檢查所有屬性來實現樂觀鎖定。
 Hibernate中透過版本號檢查來實現後更新爲主,這也是Hibernate所推薦的方式,在數據庫中加入一個VERSON欄記錄,在讀取數據時連 同版本號一同讀取,並在更新數據時遞增版本號,然後比對版本號與數據庫中的版本號,如果大於數據庫中的版本號則予以更新,否則就回報錯誤。
 以剛纔的例子,A客戶讀取賬戶餘額1000元,並連帶讀取版本號爲5的話,B客戶此時也讀取賬號餘額1000元,版本號也爲5,A客戶在領款後賬戶餘額 爲500,此時將版本號加1,版本號目前爲6,而數據庫中版本號爲5,所以予以更新,更新數據庫後,數據庫此時餘額爲500,版本號爲6,B客戶領款後要變更數據庫,其版本號爲5,但是數據庫的版本號爲6,此時不予更新,B客戶數據重新讀取數據庫中新的數據並重新進行業務流程才變更數據庫。
 以Hibernate實現版本號控制鎖定的話,我們的對象中增加一個version屬性,例如:

public class Account {

    private int version;

    ....

 

    public void setVersion(int version) {

        this.version = version;

    }

 

    public int getVersion() {

        return version;

    }

    ....

}


而在映像文件中,我們使用optimistic-lock屬性設定version控制,<id>屬性欄之後增加一個<version>標籤,例如:

<hibernate-mapping>

    <class name="onlyfun.caterpillar.Account" talble="ACCOUNT"

           optimistic-lock="version">

        <id...../>

        <version name="version" column="VERSION"/>

 

         ....

 

    </class>

</hibernate-mapping>


 設定好版本控制之後,在上例中如果B客戶試圖更新數據,將會引發StableObjectStateException例外,我們可以捕捉這個例外,在處理中重新讀取數據庫中的數據,同時將B客戶目前的數據與數據庫中的數據秀出來,讓B客戶有機會比對不一致的數據,以決定要變更的部份,或者您可以設計程 式自動讀取新的資料,並重復扣款業務流程,直到數據可以更新爲止,這一切可以在背景執行,而不用讓您的客戶知道。

發佈了106 篇原創文章 · 獲贊 0 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章