前言
Spring的聲明式事務(wù)讓我們不在編寫獲得連接称龙、關(guān)閉連接胰坟、開啟事務(wù)因篇、提交事務(wù)、回滾事務(wù)等代碼笔横,通過一個(gè)簡單的@Transactional注解惜犀,就讓我們輕松進(jìn)行事務(wù)處理。我們知道Spring事務(wù)基于AOP狠裹,采用動(dòng)態(tài)代理實(shí)現(xiàn),雖然使用簡單汽烦,但是在實(shí)際場景中涛菠,我們也會遇到一些坑。而往往遇到坑之后撇吞,我們都會茫然俗冻,這是由于沒有對Spring事務(wù)的實(shí)現(xiàn)機(jī)制做一點(diǎn)了解導(dǎo)致的。因此本篇博客將從原理的角度分析下動(dòng)態(tài)代理給Spring事務(wù)埋下的坑牍颈!
從動(dòng)態(tài)代理到Spring事務(wù)
UserService:
txMethod和txMethod2方法模擬事務(wù)方法(相當(dāng)于@Transactional)
noTxMethod方法是普通方法
UserServiceImpl:
在Spring事務(wù)中迄薄,我們往往是在Service層進(jìn)行事務(wù)控制。
我們在UserServiceImpl中想模擬的是:
一個(gè)有事務(wù)的方法煮岁,去調(diào)用另一個(gè)有事務(wù)的方法讥蔽,會怎么樣?
一個(gè)沒有事務(wù)的方法画机,去調(diào)用一個(gè)有事務(wù)的方法冶伞,會怎么樣?
UserHandler:
這里為了簡便步氏,通過方法名稱來判斷是否開啟事務(wù)响禽。
顯然,txMethod方法、txMethod2方法都“應(yīng)該”開啟事務(wù)芋类。
UserTest:
下面隆嗅,我們來說下運(yùn)行結(jié)果:
proxyInstance.txMethod2()方法,會開啟事務(wù)侯繁,這沒有問題胖喳。
proxyInstance.txMethod()方法,雖然在事務(wù)方法txMethod()內(nèi)部調(diào)用了txMethod2()事務(wù)方法巫击,但是并沒有新開啟事務(wù)禀晓。
proxyInstance.noTxMethod()方法,雖然在沒有事務(wù)的方法noTxMethod()內(nèi)部調(diào)用了有事務(wù)的txMethod2()方法坝锰,但是并沒有開啟事務(wù)粹懒。
下面讓我們來對應(yīng)下Spring事務(wù)中的現(xiàn)象:
上述的情況,說白了顷级,就是在一個(gè)Service內(nèi)部凫乖,事務(wù)方法之間的嵌套調(diào)用,普通方法和事務(wù)方法之間的嵌套調(diào)用弓颈,都不會開啟新的事務(wù)帽芽!
為什么會這樣呢?
其實(shí)通過上面的動(dòng)態(tài)代理的代碼翔冀,你應(yīng)該可以發(fā)現(xiàn):
動(dòng)態(tài)代理最終都是要調(diào)用原始對象的导街,而原始對象在去調(diào)用方法時(shí),是不會再觸發(fā)代理了纤子!
那么如何解決呢搬瑰?
很簡單,我們完全可以在抽出一個(gè)XxxService控硼,在其內(nèi)部調(diào)用UserService.txMethod()和UserService.txMethod2()方法即可泽论。總而言之卡乾,避免在一個(gè)Service內(nèi)部進(jìn)行事務(wù)方法的嵌套調(diào)用R磴病(因?yàn)閯?dòng)態(tài)代理導(dǎo)致這種場景事務(wù)失效了。)
好像Spring事務(wù)如此簡單幔妨,但是背后卻有這些道道鹦赎,你被坑過么?
have a good weekend~
2017.11.04 zhangfengzhe