Spring事務(wù)管理零基礎(chǔ)入門(mén)
一、簡(jiǎn)介
概念:事務(wù)是數(shù)據(jù)庫(kù)操作的最小工作單元,是作為單個(gè)邏輯工作單元執(zhí)行的一系列操作,這些操作一起提交,要么都執(zhí)行,要么都不執(zhí)行。事務(wù)時(shí)一組不可分割的操作集合(工作邏輯單元)。
簡(jiǎn)而言之,就是一系列操作要么都執(zhí)行成功(事務(wù)提交),要么都執(zhí)行失?。ㄊ聞?wù)回滾)
二、特性(一原持久隔離)
2.1 原子性
事務(wù)中所有操作是不可再分割的原子單位。事務(wù)中所有操作要么都執(zhí)行成功,要么都執(zhí)行失敗
2.2 一致性(類(lèi)似能量守恒)
事務(wù)執(zhí)行后,數(shù)據(jù)庫(kù)狀態(tài)與其他業(yè)務(wù)規(guī)則保持一致,保證數(shù)據(jù)的一致性
2.3 隔離性
在并發(fā)操作中,不同事務(wù)之間應(yīng)該隔離開(kāi),使每個(gè)并發(fā)的事務(wù)不會(huì)相互干擾
2.4 持久性
一旦事務(wù)提交成功,事務(wù)中所有的數(shù)據(jù)操作都必須持久化到數(shù)據(jù)庫(kù)中,即使提交事務(wù)后,數(shù)據(jù)庫(kù)立馬崩潰,在數(shù)據(jù)庫(kù)重啟時(shí),也必須能通過(guò)某種機(jī)制恢復(fù)數(shù)據(jù)
三、隔離級(jí)別
3.1 事務(wù)級(jí)別(從低到高)
Read uncommitted:
讀未提交,一個(gè)事務(wù)可以讀取另一個(gè)未提交事務(wù)的數(shù)據(jù)。會(huì)產(chǎn)生臟讀。
Read committed:
讀提交,一個(gè)事務(wù)要等另一個(gè)事務(wù)提交后才能讀取數(shù)據(jù),會(huì)產(chǎn)生不可重復(fù)讀。
Repeatable read:
重復(fù)讀,開(kāi)始讀取數(shù)據(jù)(事務(wù)開(kāi)啟)時(shí),不再允許修改操作,可能出現(xiàn)幻讀。
Seriazable:
最高的事務(wù)隔離級(jí)別,該級(jí)別下事務(wù)串行化順序執(zhí)行,可避免臟讀、不可重復(fù)讀、幻讀,但是該事務(wù)級(jí)別效率低下,比較耗數(shù)據(jù)庫(kù)性能,一般不使用。
3.2 常用數(shù)據(jù)庫(kù)默認(rèn)級(jí)別:
Sql Server、Oracle 默認(rèn)事務(wù)隔離級(jí)別: Read committed
Mysql 默認(rèn)隔離級(jí)別是:Repeatable read
3.3 事務(wù)中可能出現(xiàn)的問(wèn)題:
臟讀(讀取了未提交的新事物,然后回滾了)
A 事務(wù)讀取了 B 事務(wù)中未提交的數(shù)據(jù), 如果事務(wù) B 回滾,則 A 讀取使用了錯(cuò)誤的數(shù)據(jù)。
不可重復(fù)讀(讀取了提交的新事物,指更新操作)
在對(duì)于數(shù)據(jù)庫(kù)中某個(gè)數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個(gè)事務(wù)修改了。
幻讀(讀取了新提交的事務(wù),指增加刪除操作)
在事務(wù) A 多次讀取構(gòu)成中,事務(wù) B 對(duì)數(shù)據(jù)進(jìn)行了新增/刪除操作,導(dǎo)致 事務(wù) A 多次讀取的數(shù)據(jù)不一致。
第一類(lèi)事務(wù)丟失(回滾丟失)
事務(wù) A、B 同時(shí)執(zhí)行一個(gè)數(shù)據(jù),事務(wù) B 已經(jīng)提交,事務(wù) A 回滾了,B 的事務(wù)操作就因?yàn)槭聞?wù) A 回滾而丟失了
第二類(lèi)事務(wù)丟失(提交覆蓋丟失)
事務(wù) A、B 同時(shí)執(zhí)行一個(gè)數(shù)據(jù),兩個(gè)同時(shí)獲取到一個(gè)數(shù)據(jù),事務(wù) B 先提交, 事務(wù) A 后提交,則事務(wù) A 覆蓋了事務(wù) B
四、傳播特性
事務(wù)的傳播性分為以下三類(lèi),所有的都是給內(nèi)部方法配置
4.1 死活都不要事務(wù)
Never:外部方法沒(méi)有事務(wù)就非事務(wù)執(zhí)行,有就拋出異常
Not_Supported:外部方法沒(méi)有事務(wù)就非事務(wù)執(zhí)行,有就直接掛起,然后非事務(wù)執(zhí)行
4.2 可有可無(wú)的
Supported:外部方法有事務(wù)就用,沒(méi)有就算了
4.3 必須要有事務(wù)
Requires_new:不管外部方法有沒(méi)有事務(wù)都新建事務(wù),如果外部有,就將外部事務(wù)掛起
Nested:如果外部方法沒(méi)有事務(wù),就新建一個(gè)事務(wù),如果外部有事務(wù),就在外部事務(wù)中嵌套事務(wù)
Required:如果外部方法沒(méi)有事務(wù)就新建一個(gè)事務(wù),如果有,就加入外部方法的事務(wù),這個(gè)是最常用的,也是默認(rèn)的
Mandatory:如果外部方法沒(méi)有事務(wù)就拋出異常,如果有,就使用外部方法的事務(wù)
五、應(yīng)用
5.1 數(shù)據(jù)表
5.2 實(shí)體類(lèi)
import lombok.Data; import javax.persistence.*; @Data @Entity public class User { @Id @GeneratedValue private Integer id; private String name; private double money; }
5.3 Service
package com.dily.study.work.service; import com.dily.study.work.entity.User; import com.dily.study.work.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired // 使用jpa private UserRepository userRepository; /** * 轉(zhuǎn)出 * * @param fromName 從誰(shuí)轉(zhuǎn)出 * @param money 轉(zhuǎn)出金額 */ public void out(String fromName, int money) { User user = userRepository.findByName(fromName); user.setMoney(user.getMoney() - money); userRepository.save(user); } /** * 轉(zhuǎn)入 * * @param toName 轉(zhuǎn)到哪里 * @param money 轉(zhuǎn)入金額 */ public void in(String toName, int money) { User user = userRepository.findByName(toName); user.setMoney(user.getMoney() + money); userRepository.save(user); } /** * 帶事務(wù) * 要么都成功,要么都失敗 * * @param fromName 從哪里轉(zhuǎn)出 * @param toName 轉(zhuǎn)入到哪里 * @param money 金額 */ @Transactional public void transfer(String fromName, String toName, int money) { out(fromName, money); if (true) throw new RuntimeException("出錯(cuò)了"); in(toName, money); } /** * 不帶事務(wù) * 只有轉(zhuǎn)出成功,轉(zhuǎn)入失敗 * * @param fromName 從哪里轉(zhuǎn)出 * @param toName 轉(zhuǎn)入到哪里 * @param money 金額 */ public void transfer(String fromName, String toName, int money) { out(fromName, money); if (true) throw new RuntimeException("出錯(cuò)了"); in(toName, money); } }
事務(wù)的嵌套
// 在 UserService 中注入自己,因?yàn)槿绻麅?nèi)部調(diào)用自己的方法,事務(wù)注解不生效。 @Autowired private UserService userService; /** * 外層事務(wù),外層只轉(zhuǎn)出 * * @param fromName 從哪里轉(zhuǎn)出 * @param toName 轉(zhuǎn)入到哪里 * @param money 金額 */ @Transactional public void laoda(String fromName, String toName, int money) { userService.out(fromName, money); if (true) throw new RuntimeException("出錯(cuò)了"); userService.xiaodi(toName,money); } /** * 內(nèi)層事務(wù),內(nèi)層只轉(zhuǎn)入 * 可以修改 propagation 的值來(lái)查看不同傳播類(lèi)型的效果 * * @param toName 轉(zhuǎn)入到哪里 * @param money 金額 */ @Transactional(propagation = Propagation.MANDATORY) public void xiaodi(String toName, int money) { if (true) throw new RuntimeException("出錯(cuò)了"); userService.in(toName, money); }
內(nèi)外部方法盡量避免操作同一張表,當(dāng)外部方法事務(wù)掛起時(shí),則外部操作的表會(huì)被加鎖,內(nèi)部方法事務(wù)則無(wú)法操作同一張表
到此這篇關(guān)于Spring事務(wù)管理零基礎(chǔ)入門(mén)的文章就介紹到這了,更多相關(guān)Spring事務(wù)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java的SimpleDateFormat線程不安全的幾種解決方案
但我們知道SimpleDateFormat是線程不安全的,處理時(shí)要特別小心,要加鎖或者不能定義為static,要在方法內(nèi)new出對(duì)象,再進(jìn)行格式化,本文就介紹了幾種方法,感興趣的可以了解一下2021-08-08prometheus監(jiān)控springboot應(yīng)用簡(jiǎn)單使用介紹詳解
這篇文章主要介紹了prometheus監(jiān)控springboot應(yīng)用簡(jiǎn)單使用介紹詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05tomcat報(bào)錯(cuò):Wrapper cannot find servlet class ...問(wèn)題解決
這篇文章主要介紹了tomcat報(bào)錯(cuò):Wrapper cannot find servlet class ...問(wèn)題解決的相關(guān)資料,需要的朋友可以參考下2016-11-11Matplotlib可視化之自定義顏色繪制精美統(tǒng)計(jì)圖
matplotlib提供的所有繪圖都帶有默認(rèn)樣式.雖然這可以進(jìn)行快速繪圖,但有時(shí)可能需要自定義繪圖的顏色和樣式,以對(duì)繪制更加精美、符合審美要求的圖像.matplotlib的設(shè)計(jì)考慮到了此需求靈活性,很容易調(diào)整matplotlib圖形的樣式,需要的朋友可以參考下2021-06-06IDEA2023隱藏.idea和.iml文件的實(shí)現(xiàn)步驟
IDEA新建項(xiàng)目會(huì)自動(dòng)生成一個(gè).idea文件夾和.iml文件,本文主要介紹了IDEA2023隱藏.idea和.iml文件的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09在SpringBoot項(xiàng)目中利用maven的generate插件
今天小編就為大家分享一篇關(guān)于在SpringBoot項(xiàng)目中利用maven的generate插件,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01使用Sentinel實(shí)現(xiàn)流控和服務(wù)降級(jí)的代碼示例
Sentinel是面向分布式、多語(yǔ)言異構(gòu)化服務(wù)架構(gòu)的流量治理組件,本文將詳細(xì)為大家介紹如何使用Sentinel實(shí)現(xiàn)流控和服務(wù)降級(jí),文中有相關(guān)的代碼示例,需要的朋友可以參考下2023-05-05Eclipse插件開(kāi)發(fā)實(shí)現(xiàn)控制臺(tái)輸出信息的方法
今天小編就為大家分享一篇關(guān)于Eclipse插件開(kāi)發(fā)實(shí)現(xiàn)控制臺(tái)輸出信息的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01