解決方法A調(diào)用方法B的事務(wù)控制問題
關(guān)于方法A調(diào)用方法B的事務(wù)控制問題

實(shí)測,不管是上圖還是下圖,得到的結(jié)論都是一致的,那就是:
前提是同一個(gè)類里的方法調(diào)用,controller層類調(diào)用service的B方法,事務(wù)自然會(huì)生效的
a.異常發(fā)生后,被調(diào)用方法(B)是否添加事務(wù)控制,對(duì)于事務(wù)的回滾是否并不產(chǎn)生影響
b.調(diào)用B的方法,添加了事務(wù)控制才能實(shí)現(xiàn)異常事務(wù)回滾,不管被調(diào)用方法B是否有事務(wù)控制
c.不管嵌套調(diào)用了多少個(gè)方法,只要最頂層方法(沒被同一個(gè)類中其他方法調(diào)用的且調(diào)用了同一個(gè)類里其他方法的方法),有事務(wù)控制,那么不管是哪個(gè)被調(diào)用的方法異常,整個(gè)調(diào)用的業(yè)務(wù)數(shù)據(jù)都回滾,不管被調(diào)用的方法是否有添加了事務(wù)的控制

其實(shí),最好的辦法是根據(jù)自己實(shí)際調(diào)用的情況,模擬測試一下就知道了。
同一個(gè)類的不同方法,A方法沒有@Transactional,B方法有@Transactional,A調(diào)用B方法,事務(wù)不起作用
問題
同一個(gè)類的不同方法,A方法沒有@Transactional,B方法有@Transactional,A調(diào)用B方法,事務(wù)不起作用
原理解析
spring 在掃描bean的時(shí)候會(huì)掃描方法上是否包含@Transactional注解,如果包含,spring會(huì)為這個(gè)bean動(dòng)態(tài)地生成一個(gè)子類(即代理類,proxy),代理類是繼承原來那個(gè)bean的。
此時(shí),當(dāng)這個(gè)有注解的方法被調(diào)用的時(shí)候,實(shí)際上是由代理類來調(diào)用的,代理類在調(diào)用之前就會(huì)啟動(dòng)transaction。
然而,如果這個(gè)有注解的方法是被同一個(gè)類中的其他方法調(diào)用的,那么該方法的調(diào)用并沒有通過代理類,而是直接通過原來的那個(gè)bean,所以就不會(huì)啟動(dòng)transaction,我們看到的現(xiàn)象就是@Transactional注解無效。
? ? //接口
? ? interface Service {
? ? ? ? void A();
? ? ? ? void B();
? ? }
? ? //目標(biāo)類,實(shí)現(xiàn)接口
? ? class ServiceImpl implements Service {
? ? ? ? //no annotation here
? ? ? ? @Override
? ? ? ? public void A() {
? ? ? ? ? ? this.B();
? ? ? ? }
?? ??? ?@Transactional
? ? ? ? @Override
? ? ? ? public void B() {
? ? ? ? ? ? System.out.println("execute doNeedTx in ServiceImpl");
? ? ? ? }
? ? }
? ? //代理類,也要實(shí)現(xiàn)相同的接口
? ? class ProxyByJdkDynamic implements Service {
? ? ? ? //包含目標(biāo)對(duì)象
? ? ? ? private Service target;
? ? ? ? public ProxyByJdkDynamic(Service target) {
? ? ? ? ? ? this.target = target;
? ? ? ? }
? ? ? ? //目標(biāo)類中此方法帶注解,進(jìn)行特殊處理
? ? ? ? @Override
? ? ? ? public void B() {
? ? ? ? ? ? //開啟事務(wù)
? ? ? ? ? ? System.out.println("-> create Tx here in Proxy");
? ? ? ? ? ? //調(diào)用目標(biāo)對(duì)象的方法,該方法已在事務(wù)中了
? ? ? ? ? ? target.B();
? ? ? ? ? ? //提交事務(wù)
? ? ? ? ? ? System.out.println("<- commit Tx here in Proxy");
? ? ? ? }
? ? ? ? //目標(biāo)類中此方法沒有注解,只做簡單的調(diào)用
? ? ? ? @Override
? ? ? ? public void A() {
? ? ? ? ? ? //直接調(diào)用目標(biāo)對(duì)象方法
? ? ? ? ? ? target.A();
? ? ? ? }
? ? }那回到一開始的問題,我們調(diào)用的方法A不帶注解,因此代理類不開事務(wù),而是直接調(diào)用目標(biāo)對(duì)象的方法。
當(dāng)進(jìn)入目標(biāo)對(duì)象的方法后,執(zhí)行的上下文已經(jīng)變成目標(biāo)對(duì)象本身了,因?yàn)槟繕?biāo)對(duì)象的代碼是我們自己寫的,和事務(wù)沒有半毛錢關(guān)系,此時(shí)你再調(diào)用帶注解的方法,照樣沒有事務(wù),只是一個(gè)普通的方法調(diào)用而已。
簡單來說,內(nèi)部調(diào)用本類方法,不會(huì)再走代理了,所以B的事務(wù)不起作用
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法
這篇文章主要介紹了Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法的相關(guān)資料,今天使用Eclipse 時(shí)出現(xiàn)以上錯(cuò)誤,本文說明如何更更正,需要的朋友可以參考下2016-11-11
Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問題解決
項(xiàng)目基于 SpringBoot + MybatisPlus 3.5.2 使用數(shù)據(jù)庫自增ID時(shí), 出現(xiàn)重復(fù)鍵的問題,本文就來介紹一下解決方法,感興趣的可以了解一下2023-09-09
Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn)
這篇文章主要介紹了Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對(duì)消息國際化的相關(guān)知識(shí),需要的朋友可以參考下2017-12-12
springbooot整合dynamic?datasource數(shù)據(jù)庫密碼加密方式
這篇文章主要介紹了springbooot整合dynamic?datasource?數(shù)據(jù)庫密碼加密方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
springboot項(xiàng)目啟動(dòng)時(shí)打印maven打包時(shí)間實(shí)現(xiàn)方式
文章介紹了通過在pom文件中配置資源過濾和新增一個(gè)配置類來映射properties文件內(nèi)字段,從而在啟動(dòng)時(shí)打印出打包時(shí)間的方法,以減少開發(fā)和運(yùn)維之間的溝通錯(cuò)誤2026-01-01
深入學(xué)習(xí)JAVA GC日志的相關(guān)知識(shí)
JVM 在Java應(yīng)用程序優(yōu)化中是不可缺少的一大重項(xiàng),如何合理配置Java參數(shù),如何驗(yàn)證配置參數(shù)的有效性,從GC日志中可以獲得很重要的提示。下面小編就帶大家來一起學(xué)習(xí)一下吧2019-06-06

