-
public
class MyEntry implements IBaseService{
-
public String A(String jsonStr) throws Exception{
-
UserInfo user =
null;
-
UserDetail userDetail =
null;
-
this.getUserMsg(user,userDetail ,jsonStr);
-
if(
null!= user){
-
this.B(user,userDetail);
-
}
-
return
"";
-
}
-
//此處需要事務
-
private String B(UserInfo user, UserDetail detail) throws DBException{
-
baseDao.saveObject(user);
-
baseDao.saveObject(detail);
-
}
-
}
<tx:method name="A" propagation="REQUIRED" />
那么如果baseDao.saveObject(detail)異常,整個B方法全部回滾。沒問題
但是
如果我在配置事務的時候僅僅對 name="B",並且不對A進行配置事務,如下:
<tx:method name="B" propagation="REQUIRED" />
那么如果baseDao.saveObject(detail)異常,方法B不能全部回滾(也就是說雖然baseDao.saveObject(detail)沒有保存成功,但是baseDao.saveObject(user)保存成功了)
在 spring 中一共定義了六種事務傳播屬性,如下
PROPAGATION_SUPPORTS -- 支持當前事務,如果當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY -- 支持當前事務,如果當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW -- 新建事務,如果當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER -- 以非事務方式執行,如果當前存在事務,則拋出異常。
PROPAGATION_NESTED -- 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。
前六個策略類似於EJB CMT,第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。
它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行為(如Spring的DataSourceTransactionManager)
研究源碼、調試程序得出結論:
A如果沒有受事務管理: 則線程內的connection 的 autoCommit為true。
B得到事務時事務傳播特性依然生效,得到的還是A使用的connection,但是 不會改變autoCommit的屬性。
所以B當中是按照每條sql進行提交的。
在一個Service內部,事務方法之間的嵌套調用,普通方法和事務方法之間的嵌套調用,都不會開啟新的事務.是因為spring采用動態代理機制來實現事務控制,而動態代理最終都是要調用原始對象的,而原始對象在去調用方法時,是不會再觸發代理了!
解決辦法:
可以把方法B放到另外一個service或者dao,然后把這個server或者dao通過@Autowired注入到方法A的bean里面,這樣即使方法A沒用事務,方法B也可以執行自己的事務了。
參考文章:
https://www.jianshu.com/p/0da29e4f354a
http://blog.csdn.net/dapinxiaohuo/article/details/52092447
http://www.iteye.com/topic/35907/