1. 程式人生 > >【Spring類的自呼叫事務失效問題】(某個類中無事務方法呼叫有事務方法)

【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,那麼,暫時還沒有找到方法來解決
-