AOP註解式事務失效問題

最近在工作中遇到使用事務。一直使用的都是註解式的事務@Transactional。完成開發自測時發現事務失效了。不科學啊,我寫的代碼怎麼可能有bug!!項目我都搭建過好幾個了,一直都是同一個套路,不可能有事務配置錯誤。於是乎分析了一下,把原因貼出來給大家共享一下。工作中肯定有踩到坑的同學。
首先說一下我的代碼結構

// 父類
public abstract class AbstractParentClass {

	public void doSomething(){
		// 1.一些通用邏輯1xxxxx
		// 2.調用抽象方法
		abstractMethod();
		// 3.一些通用邏輯2xxxxx
	}
	
	// 子類實現的抽象方法
	abstract void abstractMethod();

}
// 子類
public class Testclass extends AbstractParentClass {

	// 子類實現方法
	public void abstractMethod(){
		// 1.業務邏輯1
		// 2.調用內部方法
		methodA();
		// 3.業務邏輯2
	}

	private void methodA(){
	}

}

類的關係式是存在兩個類,父類封裝了一些通用邏輯,暴露了一個抽象方法給子類去實現。
子類對抽象方法進行了實現,方法內部又調用了自己的若干方法。

以上是代碼結構關係的介紹。相信這種設計在工作中很常見。我的情景是在子類的methodA方法中有需要加事務的操作。我就很果斷的在方法methodA上加了事務註解@Transactional

有經驗的小夥伴可能立馬就能發現一個問題,方法methodAprivate的,事務不會生效。這是一個錯誤。我開始也是把private修改成了public,但是仍然不行。
問題在哪裏呢?想一下,我們的事務是如何實現的?AOP。
比喻一下,既然是AOP的話,那得有一個觸發機制,當切面外部調用到實現類具體的方法時,穿過了切面,出發了事務。而我上面的代碼是Testclass方法abstractMethod調用了自己的方法methodA,沒有經過切面,所以沒有觸發事務。這個比喻我覺得應該有助於理解。
專業一點解釋的話呢,大家都叫這是一個AOP的缺陷。當類內部方法相互調用的時候,是不會觸發AOP的。那應該怎麼做呢,子類做如下修改:

// 子類
public class Testclass extends AbstractParentClass {

	// 子類實現方法
	public void abstractMethod(){
		// 1.業務邏輯1
		// 2.調用內部方法
		// methodA();
		// 調用方式修改爲這樣
		// 這個方法能獲取到aop對象還有一個前提,就是使用了aop。例如@Transactional加到了一個private方法上,那麼是會報錯的.而且其他配置也要配對
		 ((Testclass)AopContext.currentProxy()).methodA();
		// 3.業務邏輯2
	}
	
	@Transactional
	public void methodA(){
	}

}

記得要在xml配置中配置

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

問題根源是類內部不加事務的方法調用加了事務的方法導致的。其他類似的方法調用關係導致的AOP不生效問題可以以此類推。
關於AopContext.currentProxy()的詳細使用和配置可以單獨去查找,資料很多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章