1. 程式人生 > >spring 事務處理中,同一個類中:A方法(無事務)調B方法(有事務),事務不生效問題

spring 事務處理中,同一個類中:A方法(無事務)調B方法(有事務),事務不生效問題

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_REQUIRED -- 支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
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/