一、悲觀鎖java
它指的是對數據被外界修改保持保守態度,因些,在整個數據處理過程當中,將數據牌鎖定狀態。悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層的鎖機制才能保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系統不會修改數據)。 數據庫
一個典型的悲觀鎖調用示例: app
select * from account where name = "12345" for update ide
經過for update子句,這條SQL鎖定了account表中全部符合檢索條件的記錄。本次事務提交以前(事務提交時會釋放事務過程當中的鎖),外界沒法修改這些記錄。 函數
二、樂觀鎖性能
相對悲觀鎖而言,樂觀鎖機制採起了更加寬鬆的加鎖機制。悲觀鎖大多數狀況下依靠數據庫的鎖機制,以操做最大程度的獨佔性。但隨着而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷每每沒法承受。 測試
樂觀鎖,大可能是基於數據版本(Version)記錄機制實現。何謂數據版本?即爲數據增長一個版本標識,在基於庫表的版本解決方案中,通常是經過爲數據庫表增長version字段來實現。 this
讀取出數據時,將此版本號一同讀出,之生更新時,對此版本號加1.此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,若是提交的數據版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據。 spa
例如,兩我的同時在同一個賬號取錢,帳號有100,A取50,B取20,A先提交,B的餘額即爲80,這時就不一樣步了,A提交後版本已經變了2了,而B看到的仍是1的版本,此時B的提交必須被駁回。 .net
須要注意的是,樂觀鎖機制每每基於系統中的數據存儲邏輯,所以也具有必定的侷限性。若有些例子,因爲樂觀鎖機制是在咱們的系統中實現,來自外部系統的用戶餘額更新操做不受咱們系統控制,所以可能會形成非法數據被更新到數據庫中。
在系統設計階段,咱們應該充分考慮到某些狀況出現的可能性,並進行相應調整(如將樂觀鎖策略在數據庫存儲過程當中實現,對外只開放基於此存儲過程的數據更新途徑,而不是將數據庫表直接對外公開)。
Hibernate 在其數據訪問引擎中內置了樂觀鎖實現。若是不用考慮外部系統對數據庫的更新操做,利用Hibernate提供的透明化樂觀鎖實現,將大大提高咱們的生產力。
(1)、實體類
package learn.hibernate.bean; import java.util.Date; import java.util.HashSet; import java.util.Set; /** * 持久化類設計 * 注意: * 持久化類一般建議要有一個持久化標識符(ID) * 持久化標識符一般建議使用封裝類(例如:Integer 由於基本類型存在默認值) * 持久化類一般建議手動添加一個無參構造函數 (由於有些操做是經過放射機制進行的) * 屬性一般建議提供 getter/setter 方法 * 持久化類不能使用 final 修飾 * 持久化類中若是使用了集合類型數據,只能使用集合所對應的接口類型來聲明(List/Map/Set) * 以下:ArrayList list = new ArrayList(); 不行 * List list = new ArrayList(); 可行 */ public class Person { private Integer id; private String name; private int age; private int passwork; private Date birthday; private Integer version; public Person() { } public Person(String name, int age, int passwork, Date birthday) { super(); this.name = name; this.age = age; this.passwork = passwork; this.birthday = birthday; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + ", passwork=" + passwork + ", birthday=" + birthday + "]"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getPasswork() { return passwork; } public void setPasswork(int passwork) { this.passwork = passwork; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Integer getVersion() { return version; } public void setVersion(Integer version) { this.version = version; } }(2)、持久化映射文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="learn.hibernate.bean"> <!-- optimistic-lock="version" 指定持久化類的樂觀鎖策略 --> <class name="Person" table="t_person" optimistic-lock="version"> <id name="id" column="person_id"> <generator class="native"/> </id> <!-- 配置 鎖字段和對應的屬性關聯,以及字段類型 --> <version name="version" column="t_version" type="integer"/> <property name="name" column="t_name"/> <property name="age"/> <property name="passwork"/> <property name="birthday"/> </class> </hibernate-mapping>(3)、測試類
/** * hibernate 在獲取數據的時候返回一個鎖狀態 * 在提交數據的時候會自動的將鎖狀態進行改變 */ @Test public void testUpdate(){ Person p1 = (Person)s1.get(Person.class, 1); Person p2 = (Person)s2.get(Person.class, 1); System.out.println("----------1---start-----------"); tx = s1.beginTransaction(); p1.setName("p1"); s1.update(p1); tx.commit(); System.out.println("----------1---end-----------"); System.out.println("----------2---start-----------"); tx = s2.beginTransaction(); p2.setName("p2"); s2.update(p2); tx.commit(); System.out.println("----------2---end-----------"); }