javascript
SpringTX
文章目錄
- SpringTX的介紹
- SpringTX的使用代碼示例
- 聲明式事務(wù)中屬性解釋
- SpringBoot中AOP事務(wù)配置
SpringTX的介紹
問題:
在學(xué)習(xí)了Spring整合mybatis后,我們可以直接從Spring容器中獲取mapper層的實(shí)例化對(duì)象完成數(shù)據(jù)庫操作。而在業(yè)務(wù)層方法中很多時(shí)候因?yàn)闃I(yè)務(wù)邏輯的復(fù)雜性,會(huì)出現(xiàn)在業(yè)務(wù)層方法中調(diào)用多個(gè)數(shù)據(jù)庫操作。而之前我們學(xué)習(xí)過事務(wù)的管理,在同一個(gè)業(yè)務(wù)中只要有一個(gè)數(shù)據(jù)庫操作執(zhí)行失敗,其他的就算執(zhí)行成功也會(huì)一并回滾。但是在Spring整合Mybatis后,我們獲取的直接是Mapper接口的實(shí)例化對(duì)象,而事務(wù)的管理需要使用connection對(duì)象來完成或者SqlSession對(duì)象來完成,那么在Spring整合Mybatis后如何聲明事務(wù)管理代碼呢?
解決:
假如我們能夠從Spring容器中獲取SqlSession對(duì)象,那么在業(yè)務(wù)方法A中調(diào)用了多次的數(shù)據(jù)庫操作,我們就需要在A業(yè)務(wù)方法中的業(yè)務(wù)邏輯代碼之前開啟事務(wù)管理,在邏輯代碼之后進(jìn)行提交或者回滾。假如有10個(gè)業(yè)務(wù)方法需要聲明事務(wù)管理,則需要聲明10次,過于麻煩,而且需要修改業(yè)務(wù)方法的源碼。基于以上的流程我們發(fā)現(xiàn),該擴(kuò)展流程完全符合AOP的基本規(guī)范,考慮使用SpringAOP的方式來對(duì)業(yè)務(wù)方法進(jìn)行擴(kuò)展,聲明環(huán)繞通知,在環(huán)繞通知中聲明事務(wù)管理代碼,切點(diǎn)為要進(jìn)行事務(wù)管理的業(yè)務(wù)方法。
但是我們又無法直接獲取到SqlSession對(duì)象,造成無法在環(huán)繞通 知中聲明事務(wù)管理代碼,又發(fā)現(xiàn)事務(wù)管理的代碼是重復(fù)的代碼, 那么能不能讓Spring官方給我們直接提供一個(gè)和Spring容器直 接整合好的事務(wù)管理類。答案是可以的。
理論圖:
實(shí)現(xiàn):
Spring的TX
概念:
編程式事務(wù): 事務(wù)管理代碼由程序員自己編寫。
聲明式事務(wù): 事務(wù)管理代碼由第三方直接提供,程序員直接將其組裝到功能中即可。
[2] SpringTX的使用流程
① 導(dǎo)入相關(guān)jar包
i. SpringIOC的jar
ii. SpringAOP的jar
iii. SpringTX的jar
iv. Spring整合Mybatis的jar
v. Mybatis的jar
vi. 數(shù)據(jù)庫的驅(qū)動(dòng)的jar
② 搭建Spring整合Mybatis的項(xiàng)目
③ 在applicationcontext.xml文件中配置事務(wù)管理bean
④ 在applicationcontext.xml文件中配置業(yè)務(wù)層bean
⑤ 在applicationcontext.xml文件中配置事務(wù)管理切面
⑥ 正常編寫代碼完成功能開發(fā)。
SpringTX的使用代碼示例
[1] 在數(shù)據(jù)庫中創(chuàng)建賬戶信息表(銀行轉(zhuǎn)賬)
[2] 在web項(xiàng)目中導(dǎo)入相關(guān)的jar文件
[3] 搭建Spring整合Mybatis開發(fā)基板
① 在src下創(chuàng)建MVC包結(jié)構(gòu)
② 在src下創(chuàng)建并配置applicationcontext.xml
③ 在web.xml文件中配置Spring的資源
[4] 聲明mapper層完成銀行轉(zhuǎn)賬的數(shù)據(jù)庫操作
① 在mapper包下創(chuàng)建AccountMapper接口并聲明轉(zhuǎn)賬方法
② 在AccountMapper的數(shù)據(jù)庫操作方法上使用注解聲明SQL語句
[5] 聲明業(yè)務(wù)層方法完成銀行轉(zhuǎn)賬
① 在service層中聲明接口AccountService,并聲明轉(zhuǎn)賬方 法。
② 在service層下創(chuàng)建包impl,并聲明接口的實(shí)現(xiàn)類AccountServiceImpl,并完成轉(zhuǎn)賬業(yè)務(wù)方法功能。
[6] 在controller層聲明類TestAccount測試銀行轉(zhuǎn)賬功能
[7] 在applicationcontext.xml文件中配置Spring的事務(wù)管理(重點(diǎn)掌握)
聲明式事務(wù)中屬性解釋
1.1 支持*通配符
2.1 如果為true,告訴數(shù)據(jù)庫此事務(wù)為只讀事務(wù).數(shù)據(jù)化優(yōu)化,會(huì)對(duì)性能有一定提升,所以只要是查詢的方法,建議使用此數(shù)據(jù).
2.2 如果為false(默認(rèn)值),事務(wù)需要提交的事務(wù).建議新增,刪除,修改.
3.1 當(dāng)一個(gè)具有事務(wù)控制的方法被另一個(gè)有事務(wù)控制的方法調(diào)用后,需要如何管理事務(wù)(新建事務(wù)?在事務(wù)中執(zhí)行?把事務(wù)掛起?報(bào)異常?)
3.2 REQUIRED (默認(rèn)值): 如果當(dāng)前有事務(wù),就在事務(wù)中執(zhí)行,如果當(dāng)前沒有事務(wù),新建一個(gè)事務(wù).
3.3 SUPPORTS:如果當(dāng)前有事務(wù)就在事務(wù)中執(zhí)行,如果當(dāng)前沒有事務(wù),就在非事務(wù)狀態(tài)下執(zhí)行.
3.4 MANDATORY:必須在事務(wù)內(nèi)部執(zhí)行,如果當(dāng)前有事務(wù),就在事務(wù)中執(zhí)行,如果沒有事務(wù),報(bào)錯(cuò).
3.5 REQUIRES_NEW:必須在事務(wù)中執(zhí)行,如果當(dāng)前沒有事務(wù),新建事務(wù),如果當(dāng)前有事務(wù),把當(dāng)前事務(wù)掛起.
3.6 NOT_SUPPORTED:必須在非事務(wù)下執(zhí)行,如果當(dāng)前沒有事務(wù),正常執(zhí)行,如果當(dāng)前有事務(wù),把當(dāng)前事務(wù)掛起.
3.7 NEVER:必須在非事務(wù)狀態(tài)下執(zhí)行,如果當(dāng)前沒有事務(wù),正常執(zhí)行,如果當(dāng)前有事務(wù),報(bào)錯(cuò).
3.8 NESTED:必須在事務(wù)狀態(tài)下執(zhí)行.如果沒有事務(wù),新建事務(wù),如果當(dāng)前有事務(wù),創(chuàng)建一個(gè)嵌套事務(wù).
4.isolation=”” 事務(wù)隔離級(jí)別
4.1 在多線程或并發(fā)訪問下如何保證訪問到的數(shù)據(jù)具有完整性的.
4.2 臟讀:
4.2.1 一個(gè)事務(wù)(A)讀取到另一個(gè)事務(wù)(B)中未提交的數(shù)據(jù),另一個(gè)事務(wù)中數(shù)據(jù)可能進(jìn)行了改變,此時(shí)A事務(wù)讀取的數(shù)據(jù)可能和數(shù)據(jù)庫中數(shù)據(jù)是不一致的,此時(shí)認(rèn)為數(shù)據(jù)是臟數(shù)據(jù),讀取臟數(shù)據(jù)過程叫做臟讀.
4.3 不可重復(fù)讀:
4.3.1 主要針對(duì)的是某行數(shù)據(jù).(或行中某列)
4.3.2 主要針對(duì)的操作是修改操作.
4.3.3 兩次讀取在同一個(gè)事務(wù)內(nèi)
4.3.4 當(dāng)事務(wù)A第一次讀取事務(wù)后,事務(wù)B對(duì)事務(wù)A讀取的數(shù)據(jù)進(jìn)行修改,事務(wù)A中再次讀取的數(shù)據(jù)和之前讀取的數(shù)據(jù)不一致,過程不可重復(fù)讀.
4.4 幻讀:
4.4.1 主要針對(duì)的操作是新增或刪除
4.4.2 兩次事務(wù)的結(jié)果.
4.4.3 事務(wù)A按照特定條件查詢出結(jié)果,事務(wù)B新增了一條符合條件的數(shù)據(jù).事務(wù)A中查詢的數(shù)據(jù)和數(shù)據(jù)庫中的數(shù)據(jù)不一致的,事務(wù)A好像出現(xiàn)了幻覺,這種情況稱為幻讀.
4.5 DEFAULT: 默認(rèn)值,由底層數(shù)據(jù)庫自動(dòng)判斷應(yīng)該使用什么隔離界別
4.6 READ_UNCOMMITTED: 可以讀取未提交數(shù)據(jù),可能出現(xiàn)臟讀,不重復(fù)讀,幻讀.
4.6.1 效率最高.
4.7 READ_COMMITTED:只能讀取其他事務(wù)已提交數(shù)據(jù).可以防止臟讀,可能出現(xiàn)不可重復(fù)讀和幻讀.
4.8 REPEATABLE_READ: 讀取的數(shù)據(jù)被添加鎖,防止其他事務(wù)修改此數(shù)據(jù),可以防止不可重復(fù)讀.臟讀,可能出現(xiàn)幻讀.
4.9 SERIALIZABLE: 排隊(duì)操作,對(duì)整個(gè)表添加鎖.一個(gè)事務(wù)在操作數(shù)據(jù)時(shí),另一個(gè)事務(wù)等待事務(wù)操作完成后才能操作這個(gè)表.
4.9.1 最安全的
4.9.2 效率最低的.
5.rollback-for=”異常類型全限定路徑”
5.1 當(dāng)出現(xiàn)什么異常時(shí)需要進(jìn)行回滾
5.2 建議:給定該屬性值.
5.2.1 手動(dòng)拋異常一定要給該屬性值.
6.no-rollback-for=””
6.1 當(dāng)出現(xiàn)什么異常時(shí)不滾回事務(wù).
SpringBoot中AOP事務(wù)配置
在SpringBoot里面可以直接導(dǎo)入 Spring 的配置文件,同時(shí)大部分的開發(fā)者都是基于配置文件的形式進(jìn)行事務(wù)定義的,但是如果真的要做一個(gè)符合于 SpringBoot應(yīng)用開發(fā),那么就需要考慮避免XML配置文件的出現(xiàn),所以直接基于Bean的模式來實(shí)現(xiàn)AOP事務(wù)配置。
1、【microboot-database子模塊】編寫一個(gè)事務(wù)配置類
2、【microboot-database子模塊】既然已經(jīng)創(chuàng)建好了事務(wù)相關(guān)處理類,那么下面就在IMemberService 業(yè)務(wù)接口里面擴(kuò)充一個(gè)方法。這個(gè)方法有可能會(huì)產(chǎn)生異常。
package com.yootk.service;public interface IMemberService {public boolean addBatch(String ... mid); // 批量數(shù)據(jù)增加 } package com.yootk.service.impl.impl;import com.yootk.dao.IMemberDAO; import com.yootk.service.IMemberService; import com.yootk.vo.Member; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service public class MemberServiceImpl implements IMemberService {@Autowiredprivate IMemberDAO memberDAO;@Overridepublic boolean addBatch(String... mid) {for (String id : mid) {Member vo = new Member();vo.setMid(id); // 如果id重復(fù)則會(huì)出現(xiàn)更新異常vo.setName("老李");this.memberDAO.insert(vo);}return true;} }3、【microboot-database子模塊】在實(shí)現(xiàn)類中進(jìn)行數(shù)據(jù)的增加:
package com.yootk.test;import com.baomidou.mybatisplus.core.metadata.IPage; import com.yootk.StartSpringBootDatabaseApplication; import com.yootk.service.IMemberService; import com.yootk.vo.Member; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration;import java.util.Date; import java.util.Set;@ExtendWith(SpringExtension.class) // 使用JUnit5測試工具 @WebAppConfiguration // 啟動(dòng)WEB運(yùn)行環(huán)境 @SpringBootTest(classes = StartSpringBootDatabaseApplication.class) // 配置程序啟動(dòng)類 public class TestMemberService { // 編寫測試類@Autowiredprivate IMemberService memberService;@Testpublic void testAddBatchRepeatID() { //傳遞數(shù)據(jù)庫中已有的idthis.memberService.addBatch("muyan", "yootk", "lixinghua");}@Testpublic void testAddBatchNoRepeatID() { //傳遞數(shù)據(jù)庫中沒有有的idthis.memberService.addBatch("muyan-happy", "yootk-happy", "lixinghua-happy"");} }4、【程序執(zhí)行結(jié)果】
testAddBatchRepeatID
testAddBatchNoRepeatID
加入成功
總結(jié)
- 上一篇: SpringAOP之代理设计模式
- 下一篇: Spring的properties属性配