javascript
spring 事务原理_Spring声明式事务处理的实现原理,来自面试官的穷追拷问
公眾號(hào)[JavaQ]原創(chuàng),專注分享Java基礎(chǔ)原理分析、實(shí)戰(zhàn)技術(shù)、微服務(wù)架構(gòu)、分布式系統(tǒng)構(gòu)建,誠(chéng)邀點(diǎn)贊關(guān)注!
面試官:有如下代碼場(chǎng)景,A類的a1方法沒(méi)有標(biāo)注@Transactional注解,a2方法標(biāo)注了@Transactional注解,那么在a1方法里調(diào)用a2方法,此時(shí)會(huì)開始事務(wù)嗎?
小小白:不會(huì)開啟事務(wù)。
面試官:解釋一下為什么?
小小白:a1方法是目標(biāo)類A的原生方法,調(diào)用a1的時(shí)候即直接進(jìn)入目標(biāo)類A進(jìn)行調(diào)用,在目標(biāo)類A里面只有a2的原生方法,在a1里調(diào)用a2,即直接執(zhí)行a2的原生方法,并不通過(guò)創(chuàng)建代理對(duì)象進(jìn)行調(diào)用,所以并不會(huì)進(jìn)入TransactionInterceptor的invoke方法,不會(huì)開啟事務(wù)。
面試官:那此時(shí)如果在a1方法上標(biāo)注@Transactional注解,a2方法不標(biāo)注@Transactional注解,但是a1方法的訪問(wèn)修飾符是protected,在a1方法里調(diào)用a2方法會(huì)開始事務(wù)嗎?
小小白:也不會(huì)開啟事務(wù)。
面試官:根據(jù)你上面的回答改了代碼,為什么還是不會(huì)開啟事務(wù)?
小小白:@Transactional的工作機(jī)制是基于AOP實(shí)現(xiàn)的,而AOP是使用動(dòng)態(tài)代理實(shí)現(xiàn)的,動(dòng)態(tài)代理要么是JDK方式、要么是Cglib方式。如果是JDK動(dòng)態(tài)代理的方式,根據(jù)上面的分析可以知道,目標(biāo)類的目標(biāo)方法是在接口中定義的,也就是必須是public修飾的方法才可以被代理。如果是Cglib方式,代理類是目標(biāo)類的子類,理論上可以代理public和protected方法,但是Spring在進(jìn)行事務(wù)增強(qiáng)是否能夠應(yīng)用到當(dāng)前目標(biāo)類判斷的時(shí)候,遍歷的是目標(biāo)類的public方法,所以Cglib方式也只對(duì)public方法有效。?
面試官:Spring框架中聲明式事務(wù)處理是如何實(shí)現(xiàn)的?
小小白:Spring容器在初始化每個(gè)單例bean的時(shí)候,會(huì)遍歷容器中的所有BeanPostProcessor實(shí)現(xiàn)類,并執(zhí)行其postProcessAfterInitialization方法,在執(zhí)行AbstractAutoProxyCreator類的postProcessAfterInitialization方法時(shí)會(huì)遍歷容器中所有的切面,查找與當(dāng)前實(shí)例化bean匹配的切面,這里會(huì)獲取事務(wù)屬性切面,查找@Transactional注解及其屬性值,然后根據(jù)得到的切面創(chuàng)建一個(gè)代理對(duì)象,默認(rèn)是使用JDK動(dòng)態(tài)代理創(chuàng)建代理,如果目標(biāo)類是接口,則使用JDK動(dòng)態(tài)代理,否則使用Cglib。在創(chuàng)建代理的過(guò)程中會(huì)獲取當(dāng)前目標(biāo)方法對(duì)應(yīng)的攔截器,此時(shí)會(huì)得到TransactionInterceptor實(shí)例,在它的invoke方法中實(shí)現(xiàn)事務(wù)的開啟和回滾,在需要進(jìn)行事務(wù)操作的時(shí)候,Spring會(huì)在調(diào)用目標(biāo)類的目標(biāo)方法之前進(jìn)行開啟事務(wù)、調(diào)用異常回滾事務(wù)、調(diào)用完成會(huì)提交事務(wù)。是否需要開啟新事務(wù),是根據(jù)@Transactional注解上配置的參數(shù)值來(lái)判斷的。如果需要開啟新事務(wù),獲取Connection連接,然后將連接的自動(dòng)提交事務(wù)改為false,改為手動(dòng)提交。當(dāng)對(duì)目標(biāo)類的目標(biāo)方法進(jìn)行調(diào)用的時(shí)候,若發(fā)生異常將會(huì)進(jìn)入completeTransactionAfterThrowing方法。?
面試官:能否通俗的講述一下它的實(shí)現(xiàn)原理?
小小白:如果在類A上標(biāo)注Transactional注解,Spring容器會(huì)在啟動(dòng)的時(shí)候,為類A創(chuàng)建一個(gè)代理類B,類A的所有public方法都會(huì)在代理類B中有一個(gè)對(duì)應(yīng)的代理方法,調(diào)用類A的某個(gè)public方法會(huì)進(jìn)入對(duì)應(yīng)的代理方法中進(jìn)行處理;如果只在類A的b方法(使用public修飾)上標(biāo)注Transactional注解,Spring容器會(huì)在啟動(dòng)的時(shí)候,為類A創(chuàng)建一個(gè)代理類B,但只會(huì)為類A的b方法創(chuàng)建一個(gè)代理方法,調(diào)用類A的b方法會(huì)進(jìn)入對(duì)應(yīng)的代理方法中進(jìn)行處理,調(diào)用類A的其它public方法,則還是進(jìn)入類A的方法中處理。在進(jìn)入代理類的某個(gè)方法之前,會(huì)先執(zhí)行TransactionInterceptor類中的invoke方法,完成整個(gè)事務(wù)處理的邏輯,如是否開啟新事務(wù)、在目標(biāo)方法執(zhí)行期間監(jiān)測(cè)是否需要回滾事務(wù)、目標(biāo)方法執(zhí)行完成后提交事務(wù)等。
面試官:Spring框架對(duì)事務(wù)回滾的實(shí)現(xiàn),是不是對(duì)所有類型的異常都會(huì)進(jìn)行事務(wù)回滾操作?
小小白:Spring并不會(huì)對(duì)所有類型異常都進(jìn)行事務(wù)回滾操作,默認(rèn)是只對(duì)Unchecked Exception(Error和RuntimeException)進(jìn)行事務(wù)回滾操作。
面試官:有沒(méi)有遇到過(guò)Transactional注解的不合理用法?
小小白:當(dāng)下對(duì)數(shù)據(jù)庫(kù)連接的使用基本上都用連接池技術(shù),每個(gè)應(yīng)用會(huì)根據(jù)環(huán)境和自身需求設(shè)置一些合適的連接池配置,如果每個(gè)連接都一直被長(zhǎng)時(shí)間占用,會(huì)導(dǎo)致數(shù)據(jù)庫(kù)連接數(shù)不夠用、系統(tǒng)各項(xiàng)壓力指標(biāo)不斷攀升、系統(tǒng)緩慢等問(wèn)題,所以說(shuō)連接池中的每一個(gè)連接都是很昂貴的。那么問(wèn)題就來(lái)了,只要需要事務(wù)就需要占用一個(gè)數(shù)據(jù)庫(kù)連接,如果在需要開啟事務(wù)的方法里進(jìn)行一些IO操作、網(wǎng)絡(luò)通訊等需要長(zhǎng)時(shí)間處理的操作,這個(gè)數(shù)據(jù)庫(kù)連接就一直被占用著,直到方法執(zhí)行結(jié)束后自動(dòng)提交事務(wù)或執(zhí)行過(guò)程中發(fā)生異常回滾事務(wù),這個(gè)數(shù)據(jù)庫(kù)連接才會(huì)被釋放掉。這個(gè)過(guò)程中還有一個(gè)很可怕的問(wèn)題,如果在需要開啟事務(wù)的方法里進(jìn)行了網(wǎng)絡(luò)通訊操作,而這個(gè)操作沒(méi)有設(shè)置網(wǎng)絡(luò)超時(shí)時(shí)間,那這個(gè)數(shù)據(jù)庫(kù)連接就會(huì)被一直占用著。上述問(wèn)題,在流量很大的情況下簡(jiǎn)直就是災(zāi)難,會(huì)直接導(dǎo)致應(yīng)用系統(tǒng)掛掉。
面試官:如何解決這些問(wèn)題?
小小白:正確的使用Transactional注解需要做到如下四點(diǎn):
不要在類上標(biāo)注Transactional注解,要在需要的方法上標(biāo)注。即使類的每個(gè)方法都需要事務(wù)也不要在類上標(biāo)注,因?yàn)橛锌赡苣慊騽e人新添加的方法根本不需要事務(wù);
標(biāo)注了Transactional注解的方法體中不要涉及耗時(shí)很久的操作,如IO操作、網(wǎng)絡(luò)通信等;
根據(jù)業(yè)務(wù)需要設(shè)置合適的事務(wù)參數(shù),如是否需要新事務(wù)、超時(shí)時(shí)間等;
控制事務(wù)影響的范圍,代碼中減少事務(wù)影響的代碼。
往期推薦:
Spring MVC相關(guān)面試題就是無(wú)底洞,反正我是怕了
說(shuō)實(shí)話,面試這么問(wèn)Spring框架的問(wèn)題,我快扛不住了
沒(méi)使用加號(hào)拼接字符串,面試官竟然問(wèn)我為什么
面試官一步一步的套路你,為什么SimpleDateFormat不是線程安全的
都說(shuō)ThreadLocal被面試官問(wèn)爛了,可為什么面試官還是喜歡繼續(xù)問(wèn)
Java注解是如何玩轉(zhuǎn)的,面試官和我聊了半個(gè)小時(shí)
如何去除代碼中的多次if而引發(fā)的一連串面試問(wèn)題
三分鐘快速搞定git常規(guī)使用
String引發(fā)的提問(wèn),我差點(diǎn)跪了
就寫了一行代碼,被問(wèn)了這么多問(wèn)題
面試官:JVM對(duì)鎖進(jìn)行了優(yōu)化,都優(yōu)化了啥?
synchronized連環(huán)問(wèn)
點(diǎn)點(diǎn)"在看" 唄
總結(jié)
以上是生活随笔為你收集整理的spring 事务原理_Spring声明式事务处理的实现原理,来自面试官的穷追拷问的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: web怎么用代码创造表格_Python新
- 下一篇: python参数传递_python中的*