在一個類內部有2個方法foo和bar,其中bar方法配有註解(@Transactional),即bar是事務執行的,而foo不是事務執行,當foo方法內部調用bar方法後,bar方法的事務是不生效的。示例代碼以下:java
public class ServiceTest { public void foo(){ this.bar();//調用自身的方法; } @Transactional public void bar(){ System.out.println("this is bar"); //數據庫操做 } }
緣由以下:數據庫
Spring中經過註解來完成事務的功能,實際是經過SpringAOP來實現的,而SpringAOP中,使用this來調用自身的方法時,此對象引用上的方法直接會被調用,不會調用代理的方法(SpringAOP原理是產生代理類)。所以bar方法的事務不會生效。若是直接調用bar方法,此時事務是生效的。app
解決方法有:this
1、將bar方法放在另外一個service類中。這種方法簡單,可是形成代碼的冗餘。
spa
2、能夠將註解@Transactional放在foo方法上。這種方法形成的影響:加入foo方法的一些操做是不須要事務的,這會延長事務執行的時間。線程
3、在foo方法中不要直接使用this來調用bar方法,經過調用代理類的bar方法。代理
public void foo(){ if(null != AopContext.currentProxy()){ ((ServiceTest)AopContext.currentProxy()).bar(); }else{ bar(); } }
咱們顯示的調用了AopContext來獲取當前代理對象,而後調用其方法,這樣作還必須的一個步驟是將當前的代理暴露給線程使用,在配置文件中須要配置一個參數:code
<property name="exposeProxy"> <value>true</value> </property>
或者在application-context.xml文件中添加配置:orm
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
它是ProxyConfig的一個參數,默認是false,若是不設置這個參數,那麼上述java代碼將沒法獲取當前線程中的代理對象。xml
這種方法能夠成功觸發攔截,可是也帶來了其餘問題,好比代碼的織入,咱們的代碼將變得複雜並且晦澀,並且嚴格要求系統針對於當前的bean必須配置攔截器,不然會由於找不到攔截器而拋出異常。