【Spring類的自呼叫事務失效問題】(某個類中無事務方法呼叫有事務方法)
咋麼先來看一類
public class Demo{
@Transactional
public void insert() { /* … */ }
public void query() {
this.insert();
}
}
可能會有不少人會跟我一樣,覺得上面這種方式呼叫 query()方法時,insert()上的@Transactional註解還是會起作用的,insert()在被呼叫時,將會開啟事務。 但是,當實際操作之後,你會發現,這樣並不會開啟新的事務?
為什麼呢?
我們知道,Spring之所以可以對開啟@Transactional的方法進行事務管理,是因為Spring為當前類生成了一個代理類,然後在執行相關方法時,會判斷這個方法有沒有@Transactional註解,如果有的話,則會開啟一個事務。 但是,上面這種呼叫方式時,在呼叫query()時,使用的並不是代理物件,從而導致this.insert()時也不是代理物件,從而導致@Transactional失敗。 其實現原理是 AOP , 而 AOP 的原理是動態代理 , 在自呼叫的過程中 , 是類自身的呼叫 ,而不是代理物件去呼叫, 那麼就不會產生 AOP , 這樣 Spring就不能把你的程式碼織入到約定的流程中 , 於是就產生了現在看到的失敗場景。
換句話說,就是在spring得aop中,切面配置的是某個包下的某個方法,整個流程是載入Demo類,呼叫query()方法,再呼叫insert()方法,最終返回的是Demo類產生query()的結果,整個過程最終結果是沒有事務管控的,所以說insert()方法事務失效!僅限於同一個類下,我覺得可以這樣去理解。
那麼,對於這種情況,要怎麼處理呢?
首先,在spring的xml中加上如下配置
<aop:aspectj-autoproxy expose-proxy="true"/>
1
然後,在baz() 中,改成如下方式呼叫
public class Demo{ @Timed public void insert() { /* … */ } public void query() { ((Demo) AopContext.currentProxy()).insert(); } }
PS: 如果是通過 “@Aspect” 註解實現的 AOP,那麼,暫時還沒有找到方法來解決
-