所謂悲觀鎖:也就是說數據庫悲劇了。它是由底層數據庫控制的。
舉例;當你操作一個表的時候。他就會給加上一個鎖。只有你自己能操作這張表,在數據提交之前別人是無法操作這個表的。這就是悲觀鎖。所以它的效率也是非常低的。安全性較高。
如何用呢:
即:student student=(Studnet)session.get(Student.class,1,LockMode.UPGRADE).
執行這行代碼時它就會給你上鎖:select * from Student where id=1 for update;
只有你提交之後才別人才能操作這張表。
所謂樂觀鎖:是由應用程序提供的一種機制,這種機制既能保證多個事物併發訪問數據又能防止第二類丟失更新問題。一般開發中用樂觀鎖比較多。用悲觀鎖較少。
原理:在你操作一張student表的時候,例如查詢一個id爲1的學生。他不僅僅是根據id來查詢的。他還會根據當前表的版本號或時間戳來進行是否繼續操作。
例如你在操作一張表更新分數,你首先查詢到一個學生,查出來了她的分數,而另一個人也同時在獲取到了這個學生的分數也要對其更新。當你進行更新的時候,首先hibernate會幫你查看數據表的version是多少,如果你們的version相等,就會更新當前的version自增1,同時也更新了分數,那麼就更新成功。當你提交後,另一個人再對其更新,他也是根據id和當前的version來更新分數,但是他發現這時候,version並不相等。因爲你已經更新了啊。所以他就會拋出一個異常:StaleObjectStaleException的異常。
好看一張圖你就明白了。
那麼如何實現樂觀鎖呢。有兩種方式:
可以利用hibernate提供的版本功能來實現樂觀鎖,對象-關係映射文件中的<version>元素和<timestamp>元素都具有版本控制功能
1.<version>元素:通過利用一個遞增的整數來跟蹤數據庫表中記錄的版本,
2.<timestamp>元素利用時間戳來跟蹤數據庫表中記錄的版本
第一種方式:
首先在類裏面添加一個字段:private int version 並提供getter,setter方法
然後在映射文件中添加一個元素:<version name="version" column="version" type="int"></version>
當然你的表裏面必須要有這個version字段啊。
第二種方式:
和第一種方式本質上是一樣的。
首先在類裏面添加一個字段:private Date version 並提供getter,setter方法
然後在映射文件中添加一個元素:<timestamp name="version" column="version" type="date"></timestamp>
表裏面也必須要有這個version字段啊。
還有第三種方式。比較少用。就是當你的數據庫不能變更的時候。不能添加字段的時候可以在映射文件中的class中添加一個屬性:optimistic-lock="all"
這種方式和上面兩張方式不一樣了。例如更新的時候。他會最大限度的精確當前這個對象。加載當前對象的所有屬性值。
updte student set grade=100 where id=1 and name="zhangsan" and age=18
over.....