面试官:你知道哪几种事务失效的场景?
前言
聲明式事務(wù)是Spring功能中最爽之一,可是有些時(shí)候,我們?cè)谑褂寐暶魇绞聞?wù)并未生效,這是為什么呢?
今天陳某帶大家來聊一聊聲明事務(wù)的幾種失效場景。本文將會(huì)從以下兩個(gè)方面來說一下事務(wù)為什么會(huì)失效?
@Transactional介紹
@Transactional失效場景
這是我歷時(shí)三個(gè)月總結(jié)的?Java 面試 + Java 后端技術(shù)學(xué)習(xí)指南,本人這幾年及春招的總結(jié),目前,已經(jīng)拿到了大廠offer,拿去不謝!(目錄部分截圖)
下載方式
1.?首先掃描下方二維碼
2.?后臺(tái)回復(fù)「Java面試」即可獲取
@Transactional介紹
@Transactional是聲明式事務(wù)的注解,可以被標(biāo)記在類上、接口、方法上。
該注解中有很多值得深入了解的幾種屬性,我們來看一下。
transactionManager
指定事務(wù)管理器,值為bean的名稱,這個(gè)主要用于多事務(wù)管理器情況下指定。比如多數(shù)據(jù)源配置的情況下。
isolation
事務(wù)的隔離級(jí)別,默認(rèn)是Isolation.DEFAULT。
幾種值的含義如下:
Isolation.DEFAULT:事務(wù)默認(rèn)的隔離級(jí)別,使用數(shù)據(jù)庫默認(rèn)的隔離級(jí)別。
Isolation.READ_UNCOMMITTED:這是事務(wù)最低的隔離級(jí)別,它充許別外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數(shù)據(jù)。這種隔離級(jí)別會(huì)產(chǎn)生臟讀,不可重復(fù)讀和幻讀。
Isolation.READ_COMMITTED:保證一個(gè)事務(wù)修改的數(shù)據(jù)提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)。這種事務(wù)隔離級(jí)別可以避免臟讀出現(xiàn),但是可能會(huì)出現(xiàn)不可重復(fù)讀和幻讀。
Isolation.REPEATABLE_READ:這種事務(wù)隔離級(jí)別可以防止臟讀,不可重復(fù)讀。但是可能出現(xiàn)幻讀。
Isolation.SERIALIZABLE:這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。除了防止臟讀,不可重復(fù)讀外,還避免了幻讀。
propagation
代表事務(wù)的傳播行為,默認(rèn)值為Propagation.REQUIRED。
Propagation.REQUIRED:如果存在一個(gè)事務(wù),則支持當(dāng)前事務(wù)。如果沒有事務(wù)則開啟一個(gè)新的事務(wù)。比如A方法內(nèi)部調(diào)用了B方法,此時(shí)B方法將會(huì)使用A方法的事務(wù)。
Propagation.MANDATORY:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
Propagation.NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
Propagation.NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
Propagation.REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。比如A方法使用默認(rèn)的事務(wù)傳播屬性,B方法使用REQUIRES_NEW,此時(shí)A方法在內(nèi)部調(diào)用B方法,一旦A方法出現(xiàn)異常,A方法中的事務(wù)回滾了,但是B方法并沒有回滾,因?yàn)锳和B方法使用的不是同一個(gè)事務(wù),B方法新建了一個(gè)事務(wù)。
Propagation.NESTED:支持當(dāng)前事務(wù),新增Savepoint點(diǎn),也就是在進(jìn)入子事務(wù)之前,父事務(wù)建立一個(gè)回滾點(diǎn),與當(dāng)前事務(wù)同步提交或回滾。子事務(wù)是父事務(wù)的一部分,在父事務(wù)還未提交時(shí),子事務(wù)一定沒有提交。嵌套事務(wù)一個(gè)非常重要的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)。外層事務(wù)失敗時(shí),會(huì)回滾內(nèi)層事務(wù)所做的動(dòng)作。而內(nèi)層事務(wù)操作失敗并不會(huì)引起外層事務(wù)的回滾。
timeout
事務(wù)的超時(shí)時(shí)間,單位為秒。
readOnly
該屬性用于設(shè)置當(dāng)前事務(wù)是否為只讀事務(wù),設(shè)置為true表示只讀,false則表示可讀寫,默認(rèn)值為false。如果一個(gè)事務(wù)只涉及到只讀,可以設(shè)置為true。
rollbackFor 屬性
用于指定能夠觸發(fā)事務(wù)回滾的異常類型,可以指定多個(gè)異常類型。
默認(rèn)是在RuntimeException和Error上回滾。
noRollbackFor
拋出指定的異常類型,不回滾事務(wù),也可以指定多個(gè)異常類型。
@Transactional失效場景
聲明式事務(wù)失效的場景有很多,陳某這里只是羅列一下幾種常見的場景。
底層數(shù)據(jù)庫引擎不支持事務(wù)
如果數(shù)據(jù)庫引擎不支持事務(wù),則Spring自然無法支持事務(wù)。
在非public修飾的方法使用
@Transactional注解使用的是AOP,在使用動(dòng)態(tài)代理的時(shí)候只能針對(duì)public方法進(jìn)行代理,源碼依據(jù)在AbstractFallbackTransactionAttributeSource類中的computeTransactionAttribute方法中,如下:
此處如果不是標(biāo)注在public修飾的方法上并不會(huì)拋出異常,但是會(huì)導(dǎo)致事務(wù)失效。
異常被 " 踹死了 "
這種情況小白是最容易犯錯(cuò)的,在整個(gè)事務(wù)的方法中使用try-catch,導(dǎo)致異常無法拋出,自然會(huì)導(dǎo)致事務(wù)失效。偽代碼如下:
方法中調(diào)用同類的方法
簡單的說就是一個(gè)類中的A方法(未標(biāo)注聲明式事務(wù))在內(nèi)部調(diào)用了B方法(標(biāo)注了聲明式事務(wù)),這樣會(huì)導(dǎo)致B方法中的事務(wù)失效。
代碼如下:
為什么會(huì)失效呢?:其實(shí)原因很簡單,Spring在掃描Bean的時(shí)候會(huì)自動(dòng)為標(biāo)注了@Transactional注解的類生成一個(gè)代理類(proxy),當(dāng)有注解的方法被調(diào)用的時(shí)候,實(shí)際上是代理類調(diào)用的,代理類在調(diào)用之前會(huì)開啟事務(wù),執(zhí)行事務(wù)的操作,但是同類中的方法互相調(diào)用,相當(dāng)于this.B(),此時(shí)的B方法并非是代理類調(diào)用,而是直接通過原有的Bean直接調(diào)用,所以注解會(huì)失效。
如何解決呢?:這就涉及到注解失效的原因了,后續(xù)文章會(huì)介紹到,這里不過多介紹了。
rollbackFor屬性設(shè)置錯(cuò)誤
很容易理解,指定異常觸發(fā)回滾,一旦設(shè)置錯(cuò)誤,導(dǎo)致一些異常不能觸發(fā)回滾,此時(shí)的聲明式事務(wù)不就失效了嗎。
noRollbackFor屬性設(shè)置錯(cuò)誤
這個(gè)和rollbackFor屬性設(shè)置錯(cuò)誤類似,一旦設(shè)置錯(cuò)誤,也會(huì)導(dǎo)致異常不能觸發(fā)回滾,此時(shí)的聲明式事務(wù)會(huì)失效。
propagation屬性設(shè)置錯(cuò)誤
事務(wù)的傳播屬性在上面已經(jīng)介紹了,默認(rèn)的事務(wù)傳播屬性是Propagation.REQUIRED,但是一旦配置了錯(cuò)誤的傳播屬性,也是會(huì)導(dǎo)致事務(wù)失效,如下三種配置將會(huì)導(dǎo)致事務(wù)失效:
Propagation.SUPPORTS
Propagation.NOT_SUPPORTED
Propagation.NEVER
原始SSM項(xiàng)目,重復(fù)掃描導(dǎo)致事務(wù)失效
在原始的SSM項(xiàng)目中都配置了context:component-scan并且同時(shí)掃描了service層,此時(shí)事務(wù)將會(huì)失效。
按照Spring配置文件的加載順序來說,會(huì)先加載Springmvc的配置文件,如果在加載Springmvc配置文件的時(shí)候把service也加載了,但是此時(shí)事務(wù)還沒加載,將會(huì)導(dǎo)致事務(wù)無法成功生效。
解決方法很簡單,把掃描service層的配置設(shè)置在Spring配置文件或者其他配置文件中即可。
總結(jié)
事務(wù)失效的原因很多,但是千萬不要做到一知半解,只有深入理解了,才能在面試過程中對(duì)答如流。
今天的文章就到此結(jié)束了,如果覺得陳某寫得不錯(cuò),有所收獲的,關(guān)注在看來一波,你們的鼓勵(lì),將會(huì)是我寫作的動(dòng)力,謝謝支持!!!
最后,再附上我歷時(shí)三個(gè)月總結(jié)的?Java 面試 + Java 后端技術(shù)學(xué)習(xí)指南,這是本人這幾年及春招的總結(jié),目前,已經(jīng)拿到了大廠offer,拿去不謝!(目錄部分截圖)
下載方式
1.?首先掃描下方二維碼
2.?后臺(tái)回復(fù)「Java面試」即可獲取
總結(jié)
以上是生活随笔為你收集整理的面试官:你知道哪几种事务失效的场景?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Maven】maven 插件开发实战
- 下一篇: 为什么程序员都不喜欢使用switch,而