Transactional注解失效場景

一甜滨、Transaction:

Spring中提供了很好的事務(wù)管理機制--編程式事務(wù)和聲明式事務(wù)衣摩。編程式事務(wù)管理是侵入性事務(wù)管理昭娩,使用TransactionTemplate或者PlatformTransactionManager手動管理事務(wù)的提交栏渺、回滾等操作锐涯。其中聲明式事務(wù)建立在AOP之上纹腌,原理是對方法進行攔截,在目標方法執(zhí)行之前添加事務(wù)莱褒,目標方法執(zhí)行后根據(jù)執(zhí)行情況進行事務(wù)的提交或回滾广凸。編程式事務(wù)是侵入式的蛛枚,聲明式事務(wù)是非侵入性的,因此扭吁,提倡使用聲明式事務(wù)侥袜。@Transactional注解是實現(xiàn)聲明式事務(wù)的方式之一系馆。

1.1作用域

@Transaction 可以作用在類由蘑、接口代兵、方法上

類上:表示給該類所有的 public 方法添加上 @Transaction 注解

接口上:只有在使用基于接口的代理時它才會生效植影。像 CGLib 動態(tài)代理采用繼承的方式將會導(dǎo)致 @Transactional 注解失效思币。不推薦使用

方法上:事務(wù)的作用域就只在該方法上生效,并且如果類及方法上都配置 @Transaction 注解時惶我,方法的注解會覆蓋類上的注解

1.2屬性

屬性說明

1)valuevalue 主要用來指定不同的事務(wù)管理器,滿足在同一個系統(tǒng)中听怕,存在不同的事務(wù)管理器虑绵。如果在 Spring 中翅睛,配置了多個數(shù)據(jù)源聲明了多個事務(wù)管理器宏所,可以通過該參數(shù)來進行指定事務(wù)管理器爬骤。

2)propagation

枚舉值含義

3)isolation

4)rollbackFor 和 rollbackForClassNamerollbackFor:通過類進行指定骤铃,如@Transactional(rollbackFor = {Exception.class})

rollbackForClassName:通過類名進行指定,如@Transaction(rollbackForClassName = {"java.lang.Exception"})

5)noRollbackFor 和 noRollbackForClassName與4)一致

6)手動回滾TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

二喊暖、總覽:


三陵叽、失效場景

3.1丛版、代理異常導(dǎo)致

Spring中對注解解析的都是基于代理的页畦,如果目標方法無法被Spring代理到豫缨,那么它將無法被Spring進行事務(wù)管理。

Spring生成代理的方式有兩種:

(1)基于接口的JDK動態(tài)代理燃箭,要求目標代理類需要實現(xiàn)一個接口才能被代理

(2)基于實現(xiàn)目標類子類的CGLIB代理Spring在2.0之前遍膜,目標類如果實現(xiàn)了接口瓢颅,則使用JDK動態(tài)代理方式挽懦,否則通過CGLIB子類的方式生成代理信柿。而在2.0版本之后渔嚷,如果不在配置文件中顯示的指定spring.aop.proxy-tartget-class的值稠曼,默認情況下生成代理的方式為CGLIB形病,如下圖

3.1.1 將注解標注在接口方法上

@Transactional是支持標注在方法與類上的。一旦標注在接口上,對應(yīng)接口實現(xiàn)類的代理方式如果是CGLIB漠吻,將通過生成子類的方式生成目標類的代理量瓜,將無法解析到@Transactional,從而事務(wù)失效途乃。

3.1.2 被final绍傲、static關(guān)鍵字修飾的類或方法

事務(wù)的管理是通過代理執(zhí)行的方式生效的,如果是方法內(nèi)部調(diào)用耍共,將不會走代理邏輯烫饼,也就調(diào)用不到了。

3.1.3 類方法內(nèi)部調(diào)用

事務(wù)的管理是通過代理執(zhí)行的方式生效的划提,如果是方法內(nèi)部調(diào)用伊履,將不會走代理邏輯,也就調(diào)用不到哄辣。


解決方式:方式1:新建一個Service,將方法遷移過去崖面,使被調(diào)用方獨立出去甲棍。

方式2:在當前類注入自己,調(diào)用createUser1時通過注入的userService調(diào)用

方式3:通過AopContext.currentProxy()獲取代理對象

3.1.4 未被Spring管理

沒有被Spring管理成為IOC容器中的一個bean呈驶,無法被事務(wù)切面代理到聋迎。

3.2 框架不支持

3.2.1 非public修飾方法

3.2.2 多線程調(diào)用

在多線程/異步線程的使用場景颅围,也會導(dǎo)致事務(wù)失效的發(fā)生;TransactionAspectSupport.prepareTransactionInfo方法中渐溶,能夠看到在完成事務(wù)的狀態(tài)配置后會綁定到當前的線程眉睹,所以異步線程/多線程的使用會導(dǎo)致事務(wù)傳播的失效慕蔚。

3.2.3 數(shù)據(jù)庫本身不支持事務(wù)

比如Mysql的Myisam存儲引擎是不支持事務(wù)的桂对,只有innodb存儲引擎才支持宅此。

3.3 配置錯誤

3.3.1 傳播機制配置錯誤

不支持事務(wù)的傳播機制為:PROPAGATION_SUPPORTS璧亮,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER搭儒。

如果配置了以上三種傳播方式的話铃岔,在發(fā)生異常的時候,事務(wù)是不會回滾的稍浆。

3.3.2 rollbackFor屬性設(shè)置錯誤

默認情況下事務(wù)僅回滾運行時異常(RuntimeException)和Error朗伶,不回滾受檢異常(例如IOException)纯丸。所以默認配置可以保證RuntimeException錯誤的回滾队橙,如果想保證非RuntimeException錯誤的回滾贮匕,需要加上rollbackFor = Exception.class參數(shù),或者其他指定的異常類型生均。

因此如果方法中拋出了IO異常录别,默認情況下事務(wù)也會回滾失敗。

我們可以通過指定@Transactional(rollbackFor = Exception.class)的方式進行全異常捕獲赵讯。

(1)受檢異常:在編譯的時候鱼响,要強制檢查的異常丈积,這種異常需要去顯示的通過try/catch來進行捕獲或者通過throws去拋出去否則程序無法通過編譯的;

(2)非受檢異常:非受檢異常表示編譯器可以不需要去強制去檢查異常唬滑,這種異常不需要去顯示去捕獲或者拋出

3.4 使用錯誤

3.4.1 異常被內(nèi)部catch

默認情況下標注了@Transactional注解的方法的事務(wù)傳播機制是REQUIRED,它的特性是支持當前事務(wù),也就說加入當前事務(wù)。我們在UserService中開始事務(wù),然后再UserService1中拋出異惩炊猓回滾UserService中的事務(wù)匙头,將其標記為只讀漫谷。

但是在UserSevice中我們捕獲了異常,此時UserService上的事務(wù)認為正常提交事務(wù)乾胶。最后在提交時發(fā)現(xiàn)事務(wù)只讀抖剿,已經(jīng)被回滾,則拋出了上述異常识窿。

因此這里如果需要對特定的異常進行捕獲處理斩郎,記得再次將異常拋出,讓最外層的事務(wù)感知到喻频。

3.4.2 嵌套事務(wù)

嵌套事務(wù)失效主要是在兩個或者多個事務(wù)嵌套在一起時缩宜,且內(nèi)外層對事務(wù)rollbackFor參數(shù)配置不一致的場景;(1)外層加上了rollbackFor = Exception.class而內(nèi)層使用默認甥温,無論內(nèi)層還是外層拋出非RuntimeException錯誤均能夠正扯突停回滾!(2)若內(nèi)層加上了rollbackFor = Exception.class而外層使用默認姻蚓,若外層拋出非RuntimeException錯誤是無法正常的回滾宋梧。若內(nèi)層拋出非RuntimeException錯誤,則都能正痴玻回滾捂龄。主要是因為在使用默認propagation配置時是使用的propagationPropagation.REQUIRED;REQUIRED的意思是說,事務(wù)嵌套的時候加叁,如果發(fā)現(xiàn)已經(jīng)有事務(wù)存在了倦沧,就加入這個事務(wù),而不是新建一個事務(wù)它匕,所以根本就不存在兩個事務(wù)展融,一直只有一個;當外層報錯的時候豫柬,此時查看事務(wù)告希,沒有增加處理非RuntimeException能力扑浸,所以代碼走完,貌似“兩個事務(wù)”暂雹,都回滾失敗了首装。當里面報錯的時候,事務(wù)已經(jīng)添加上了處理非RuntimeException能力杭跪,所以仙逻,代碼走完就回滾成功了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涧尿,隨后出現(xiàn)的幾起案子系奉,更是在濱河造成了極大的恐慌,老刑警劉巖姑廉,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缺亮,死亡現(xiàn)場離奇詭異,居然都是意外死亡桥言,警方通過查閱死者的電腦和手機萌踱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來号阿,“玉大人并鸵,你說我怎么就攤上這事∪咏В” “怎么了园担?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長枯夜。 經(jīng)常有香客問我弯汰,道長,這世上最難降的妖魔是什么湖雹? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任咏闪,我火速辦了婚禮,結(jié)果婚禮上摔吏,老公的妹妹穿的比我還像新娘汤踏。我一直安慰自己,他們只是感情好舔腾,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搂擦,像睡著了一般稳诚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瀑踢,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天扳还,我揣著相機與錄音才避,去河邊找鬼。 笑死氨距,一個胖子當著我的面吹牛桑逝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俏让,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼楞遏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了首昔?” 一聲冷哼從身側(cè)響起寡喝,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勒奇,沒想到半個月后预鬓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赊颠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年格二,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竣蹦。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡顶猜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出草添,到底是詐尸還是另有隱情驶兜,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布远寸,位于F島的核電站抄淑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏驰后。R本人自食惡果不足惜肆资,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灶芝。 院中可真熱鬧郑原,春花似錦、人聲如沸夜涕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽女器。三九已至酸役,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涣澡。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工贱呐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人入桂。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓奄薇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抗愁。 傳聞我的和親對象是個殘疾皇子馁蒂,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容