【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
【問題】
?????? Spring的聲明式事務(wù),我想就不用多介紹了吧,一句話“自從用了Spring AOP啊,事務(wù)管理真輕松啊,真輕松;事務(wù)管理代碼沒有了,腦不酸了,手不痛了,一口氣全配上了事務(wù);輕量級,測試起來也簡單,嘿!”。不管從哪個角度看,輕量級聲明式事務(wù)都是一件解放生產(chǎn)力的大好事。所以,我們“一直用它”。
????? 不過,最近的一個項(xiàng)目里,卻碰到了一個事務(wù)管理上的問題:有一個服務(wù)類,其一個聲明了事務(wù)的方法,里面做了三次插入SQL操作,但是在后面出錯回滾時,卻發(fā)現(xiàn)前面插入成功了,也是說,這個聲明了事務(wù)的方法,實(shí)際上并沒有真正啟動事務(wù)!怎么回事呢?難道Spring的聲明式事務(wù)失效了?
?
【分析】
? ? ?這個問題,表面上是事務(wù)聲明失效的問題,實(shí)質(zhì)上很可能是Spring的AOP機(jī)制實(shí)現(xiàn)角度的問題。我想到很久以前研究Spring的AOP實(shí)現(xiàn)時發(fā)現(xiàn)的一個現(xiàn)象:對于以Cglib方式增強(qiáng)的AOP目標(biāo)類,會創(chuàng)建兩個對象,一個事Bean實(shí)例本身,一個是Cglib增強(qiáng)代理對象,而不僅僅是只有后者。
? ? ?我們知道,Spring的AOP實(shí)現(xiàn)方式有兩種:1、Java代理方式;2、Cglib動態(tài)增強(qiáng)方式,這兩種方式在Spring中是可以無縫自由切換的。Java代理方式的優(yōu)點(diǎn)是不依賴第三方j(luò)ar包,缺點(diǎn)是不能代理類,只能代理接口。
Spring通過AopProxy接口,抽象了這兩種實(shí)現(xiàn),實(shí)現(xiàn)了一致的AOP方式:
現(xiàn)在看來,這種抽象同樣帶了一個缺陷,那就是抹殺了Cglib能夠直接創(chuàng)建普通類的增強(qiáng)子類的能力,Spring相當(dāng)于把Cglib動態(tài)生成的子類,當(dāng)普通的代理類了,這也是為什么會創(chuàng)建兩個對象的原因。下圖顯示了Spring的AOP代理類的實(shí)際調(diào)用過程:
因此,從上面的分析可以看出,methodB沒有被AopProxy通知到,導(dǎo)致最終結(jié)果是:被Spring的AOP增強(qiáng)的類,在同一個類的內(nèi)部方法調(diào)用時,其被調(diào)用方法上的增強(qiáng)通知將不起作用。
????
????? 而這種結(jié)果,會造成什么影響呢:
????? 1:內(nèi)部調(diào)用時,被調(diào)用方法的事務(wù)聲明將不起作用
????? 2:換句話說,你在某個方法上聲明它需要事務(wù)的時候,如果這個類還有其他開發(fā)者,你將不能保證這個方法真的會在事務(wù)環(huán)境中
????? 3:再換句話說,Spring的事務(wù)傳播策略在內(nèi)部方法調(diào)用時將不起作用。不管你希望某個方法需要單獨(dú)事務(wù),是RequiresNew,還是要嵌套事務(wù),要Nested,等等,統(tǒng)統(tǒng)不起作用。
????? 4:不僅僅是事務(wù)通知,所有你自己利用Spring實(shí)現(xiàn)的AOP通知,都會受到同樣限制。。。。
【解難】
?????
????? 問題的原因已經(jīng)找到,其實(shí),我理想中的AOP實(shí)現(xiàn),應(yīng)該是下面這樣:
使用代理
1、Proxy.insertAAA() 代理對象加了事物,這樣就可以增強(qiáng)事物。
public?void?a()?{??aopProxy.b();//即調(diào)用AOP代理對象的b方法即可執(zhí)行事務(wù)切面進(jìn)行事務(wù)增強(qiáng)??}??判斷一個Bean是否是AOP代理對象可以使用如下三種方法:
AopUtils.isAopProxy(bean)????????:?是否是代理對象;
AopUtils.isCglibProxy(bean)???????:?是否是CGLIB方式的代理對象;
AopUtils.isJdkDynamicProxy(bean)?:?是否是JDK動態(tài)代理方式的代理對象;
修改我們的代碼
this.b();-----------修改為--------->((AService) AopContext.currentProxy()).b();
?
在使用的過程中,提示錯誤:
關(guān)于AOP無法切入同類調(diào)用方法的問題,給方式使用注解@Transactional(propagation = Propagation.REQUIRED,
?? ?isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
文章參考:
https://blog.csdn.net/dapinxiaohuo/article/details/52092447
https://blog.csdn.net/aya19880214/article/details/50640596
轉(zhuǎn)載于:https://my.oschina.net/maojindaoGG/blog/1920783
總結(jié)
以上是生活随笔為你收集整理的【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Leetcode - Subsets I
- 下一篇: react源码分析-setState分析