Hibernate實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖代碼介紹
四種隔離機(jī)制不要忘記:(1,2,4,8)
1.read-uncommitted:能夠去讀那些沒(méi)有提交的數(shù)據(jù)(允許臟讀的存在)
2.read-committed:不會(huì)出現(xiàn)臟讀,因?yàn)橹挥辛硪粋€(gè)事務(wù)提交才會(huì)讀取來(lái)結(jié)果,但仍然會(huì)出現(xiàn)不可重復(fù)讀和幻讀現(xiàn)象。
4.repeatable read: MySQL 默認(rèn)??芍貜?fù)讀,讀數(shù)據(jù)讀出來(lái)之后給它加把鎖,其他人先別更新,等我用完了你再更新。你的事務(wù)沒(méi)完,其他事務(wù)就不可能改這條記錄。
8.serializable:序列化,最高級(jí)別。一個(gè)一個(gè)來(lái),不去并發(fā)。效率最低。
hibernate的隔離機(jī)制
i.hibernate.connection.isolation=2
ii.用悲觀鎖解決:repeatable read的問(wèn)題(依賴(lài)于數(shù)據(jù)庫(kù)的鎖)
a)LockMode.None 無(wú)鎖的機(jī)制,Transaction結(jié)束時(shí),切換到此模式
b)LockMode.read 在查詢(xún)的時(shí)候 hibernate會(huì)自動(dòng)獲取鎖
c)LockMode.write insert update hibernate會(huì)自動(dòng)獲取鎖
d)以上3中鎖的模式,是hibernate內(nèi)部使用的
e)LockMode.UPGRADE_NOWAIT ORACLE支持的鎖的方式
例子:
Account.java:
package com.bjsxt.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Account {
private int id;
private int balance; //BigDecimal
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
hibernate.cfg.xml中配置:
<mapping class="com.bjsxt.hibernate.Account"/>
測(cè)試:
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public void testOperation1() {
Session session = sf.openSession();
session.beginTransaction();
Account a = (Account)session.load(Account.class, 1);
int balance = a.getBalance();
//do some caculations
balance = balance - 10;
//在保存時(shí)很有可能會(huì)把在同一時(shí)期修改的給覆蓋掉
//這個(gè)時(shí)候上一把"鎖"就可以避免這個(gè)問(wèn)題
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}
//下面這個(gè)就是對(duì)上面那個(gè)例子做的修改
@Test
public void testPessimisticLock() {
Session session = sf.openSession();
session.beginTransaction();
//給它加把鎖,加鎖的機(jī)制上面已經(jīng)提到了
Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE);
int balance = a.getBalance();
//do some caculation
balance = balance - 10;
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}
這是依賴(lài)于數(shù)據(jù)庫(kù)的鎖的,也就是給數(shù)據(jù)庫(kù)一個(gè)指令,要求數(shù)據(jù)庫(kù)幫忙加鎖。
——————————————————————————————————————
iii.Hibernate(JPA)樂(lè)觀鎖定(ReadCommitted)
這不是依賴(lài)數(shù)據(jù)庫(kù)加鎖的,是在程序中加鎖的。
舉個(gè)例子:一個(gè)數(shù)據(jù)需要隔離機(jī)制(不能重復(fù)讀),這個(gè)時(shí)候在更新的字段上加"版本號(hào)"(version字段),一旦有人給它update一下,這個(gè)值就加1(version+1)。
那么這種機(jī)制是如何產(chǎn)生隔離能力的呢?
原因是事務(wù)A讀取字段的同時(shí),事務(wù)B緊接著也讀取這個(gè)字段,而且改了它,此時(shí)version變成1了。這個(gè)時(shí)候事務(wù)A就會(huì)檢查字段是否被改變了,如果被改變它也做相應(yīng)的改變,沒(méi)有改變就不改。
樂(lè)觀鎖的實(shí)現(xiàn):(@Version)
Account.java:
package com.bjsxt.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class Account {
private int id;
private int balance;
private int version;
@Version//加了這個(gè)注解就說(shuō)明這個(gè)是專(zhuān)門(mén)用來(lái)做版本標(biāo)注的
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
測(cè)試:
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public void testOptimisticLock() {
Session session = sf.openSession();
Session session2 = sf.openSession();
session.beginTransaction();
Account a1 = (Account) session.load(Account.class, 1);
session2.beginTransaction();
Account a2 = (Account) session2.load(Account.class, 1);
a1.setBalance(900);
a2.setBalance(1100);
//第一個(gè)session一旦提交,version就會(huì)+1
session.getTransaction().commit();
System.out.println(a1.getVersion());
//第二個(gè)session提交的時(shí)候,一看version不一樣就會(huì)報(bào)錯(cuò)
//出了錯(cuò)誤做個(gè)記錄,下次再提交(也可以用其他方法)
session2.getTransaction().commit();
System.out.println(a2.getVersion());
session.close();
session2.close();
}
悲觀樂(lè)觀的區(qū)別:悲觀鎖認(rèn)為一定會(huì)受到影響,我加鎖誰(shuí)也別想動(dòng)。
樂(lè)觀鎖,沒(méi)出事就好,出了事我再想辦法解決。
總結(jié)
以上就是本文關(guān)于Hibernate實(shí)現(xiàn)悲觀鎖和樂(lè)觀鎖代碼介紹的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)hibernate有所幫助。有什么問(wèn)題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家。感謝大家對(duì)本站的支持。
相關(guān)文章
Java redis存Map對(duì)象類(lèi)型數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了Java redis存Map<String,RedisCustom>對(duì)象類(lèi)型數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
SpringBoot集成Lettuce客戶(hù)端操作Redis的實(shí)現(xiàn)
本文主要介紹了SpringBoot集成Lettuce客戶(hù)端操作Redis的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11
springboot運(yùn)行jar生成的日志到指定文件進(jìn)行管理方式
這篇文章主要介紹了springboot運(yùn)行jar生成的日志到指定文件進(jìn)行管理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
基于HttpServletRequest 相關(guān)常用方法的應(yīng)用
本篇文章小編為大家介紹,基于HttpServletRequest 相關(guān)常用方法的應(yīng)用,需要的朋友參考下2013-04-04
mybatis雙重foreach如何實(shí)現(xiàn)遍歷map中的兩個(gè)list數(shù)組
本文介紹了如何解析前端傳遞的JSON字符串并在Java后臺(tái)動(dòng)態(tài)構(gòu)建SQL查詢(xún)條件,首先,通過(guò)JSONArray.fromObject()將JSON字符串轉(zhuǎn)化為JSONArray對(duì)象,遍歷JSONArray,從中提取name和infos,構(gòu)建成Map對(duì)象用于Mybatis SQL映射2024-09-09
一文帶你學(xué)會(huì)規(guī)則引擎Drools的應(yīng)用
Drools?就是一個(gè)開(kāi)源的業(yè)務(wù)規(guī)則引擎,可以很容易地與?spring?boot?應(yīng)用程序集成,這篇文章就來(lái)和大家詳細(xì)聊聊Drools的具體應(yīng)用,需要的可以參考一下2023-03-03
Java實(shí)現(xiàn)中序表達(dá)式的實(shí)例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)中序表達(dá)式的實(shí)例代碼,需要的朋友可以參考下2018-08-08
Spring boot基于JPA訪問(wèn)MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
本文主要介紹了Spring boot基于JPA訪問(wèn)MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn),Spring boot結(jié)合Jpa 能夠簡(jiǎn)化創(chuàng)建 JPA 數(shù)據(jù)訪問(wèn)層和跨存儲(chǔ)的持久層功能,用戶(hù)的持久層Dao接口只需要繼承定義好的接口,感興趣的可以了解一下2021-06-06

