學了兩天的hibernate鎖機制
今天寫個總結
hibernate鎖機制包括悲觀鎖和樂觀鎖
悲觀鎖 它指的是對數據被外界修改持保守態度
假定任何時刻存取數據時
都可能有另一個客戶也正在
存取同一筆數據
為了保持數據被操作的一致性
於是對數據采取了數據庫層次的鎖定狀態
依靠數
據庫提供的鎖機制來實現
基於jdbc實現的數據庫加鎖如下
select * from account where name=
Erica
for update
在更新的過程中
數據庫處於加鎖狀
態
任何其他的針對本條數據的操作都將被延遲
本次事務提交後解鎖
而hibernate悲觀鎖的具體實現如下
String sql=
查詢語句
;
Query query=session
createQuery(sql);
query
setLockMode(
對象
LockModel
UPGRADE);
說到這裡
就提到了hiernate的加鎖模式
LockMode
NONE
無鎖機制
LockMode
WRITE
Hibernate在Insert和Update記錄的時候會自動獲取
LockMode
READ
Hibernate在讀取記錄的時候會自動獲取
這三種加鎖模式是供hibernate內部使用的
與數據庫加鎖無關
LockMode
UPGRADE
利用數據庫的for update字句加鎖
在這裡我們要注意的是
只有在查詢開始之前(也就是hiernate生成sql語句之前)加鎖
才會真
正通過數據庫的鎖機制加鎖處理
否則
數據已經通過不包含for updata子句的sql語句加載進來
所謂的數據庫加鎖也就無從談起
但是
從系統的性能上來考慮
對於單機或小系統而言
這並不成問題
然而如果是在網絡上的
系統
同時間會有許多聯機
假設有數以百計或上千甚至更多的並發訪問出現
我們該怎麼辦?如果
等到數據庫解鎖我們再進行下面的操作
我們浪費的資源是多少?
這也就導致了樂觀鎖的產生
樂觀鎖
樂觀鎖定(optimistic locking)則樂觀的認為資料的存取很少發生同時存取的問題
因而不作數
據庫層次上的鎖定
為了維護正確的數據
樂觀鎖定采用應用程序上的邏輯實現版本控制的方法
例如若有兩個客戶端
A客戶先讀取了賬戶余額
元
之後B客戶也讀取了賬戶余額
元的數據
A客戶提取了
元
對數據庫作了變更
此時數據庫中的余額為
元
B客戶也要提取
元
根據其所
取得的資料
將為
余額
若此時再對數據庫進行變更
最後的余額就會不正確
在不實行悲觀鎖定策略的情況下
數據不一致的情況一但發生
有幾個解決的方法
一種是先更新
為主
一種是後更新的為主
比較復雜的就是檢查發生變動的數據來實現
或是檢查所有屬性來實現
樂觀鎖定
Hibernate 中透過版本號檢查來實現後更新為主
這也是Hibernate所推薦的方式
在數據庫中加
入一個VERSON欄記錄
在讀取數據時連同版本號一同讀取
並在更新數據時遞增版本號
然後比對版
本號與數據庫中的版本號
如果大於數據庫中的版本號則予以更新
否則就回報錯誤
以剛才的例子
A客戶讀取賬戶余額
元
並連帶讀取版本號為
的話
B客戶此時也讀取賬號余
額
元
版本號也為
A客戶在領款後賬戶余額為
此時將版本號加
版本號目前為
而數
據庫中版本號為
所以予以更新
更新數據庫後
數據庫此時余額為
版本號為
B客戶領款後
要變更數據庫
其版本號為
但是數據庫的版本號為
此時不予更新
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客戶有機會比對不一致的數據
以決定要變更的部份
或者您可以設計程式
自動讀取新的資料
並重復扣款業務流程
直到數據可以更新為止
這一切可以在背景執行
而不用
讓您的客戶知道
但是樂觀鎖也有不能解決的問題存在
上面已經提到過樂觀鎖機制的實現往往基於系統中的數據
存儲邏輯
在我們的系統中實現
來自外部系統的用戶余額更新不受我們系統的控制
有可能造成非
法數據被更新至數據庫
因此我們在做電子商務的時候
一定要小心的注意這項存在的問題
采用比
較合理的邏輯驗證
避免數據執行錯誤
也可以在使用Session的load()或是lock()時指定鎖定模式以進行鎖定
如果數據庫不支持所指定的鎖定模式
Hibernate會選擇一個合適的鎖定替換
而不是丟出一個例外
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28182.html