在TransactionDefinition接口中定義了七個事務傳播行爲。
PROPAGATION_REQUIRED 如果存在一個事務,則支持當前事務。如果沒有事務則開啓一個新的事務。默認行爲
PROPAGATION_SUPPORTS 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行。但是對於事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。
PROPAGATION_REQUIRES_NEW 總是開啓一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。
PROPAGATION_NOT_SUPPORTED 總是非事務地執行,並掛起任何存在的事務。
PROPAGATION_NEVER 總是非事務地執行,如果存在一個活動事務,則拋出異常
PROPAGATION_NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行
本文重點講解PROPAGATION_REQUIRED 、PROPAGATION_REQUIRES_NEW、 PROPAGATION_NESTED
實際應用中常常存在serviceA調用serviceB的情況。那具體情況下serviceA和serviceB之間的事務又是怎麼傳遞的呢。
例子1:
/** 事務默認是required*/
//@Transactional
@Service("userService")
public class UserServiceImpl implements UserServive {
@Autowired
private UserMapper userDao;
@Autowired
private CommonService commonService;
public List<UserInfo> getUsers() {
return userDao.selectUsers();
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateUserAgeById(int age, long id) {
userDao.updateUserInfoById(age, id);
commonService.updateUserExtById("未知", 1);
//int b = 1/0;
/* try {
commonService.updateUserExtById("未知", 1);
} catch (Exception e) {
// TODO: handle exception
}*/
}
}
//@Transactional
@Service("commonService")
public class CommonServiceImpl implements CommonService {
@Autowired
private UserMapper userDao;
// 如果出現運行時異常,此處會回滾 並對外拋出異常
@Transactional(propagation = Propagation.NESTED)
public void updateUserExtById(String address, long id) {
userDao.updateUserExtById(address, id);
int a = 1/0;
}
}
此例userservice中的updateUserAgeById事務聲明爲Propagation.REQUIRED,調用commonservice中的updateUserExtById方法。且此方法事務聲明爲Propagation.NESTED。按上面的解釋commonservice將運行在嵌套事務中。經過測試,當updateUserExtById
發生異常時,自身進行回滾操作,回滾到它執行之前的savepoint。並向外拋出異常,userservice可以對異常進行捕獲視情況選擇回滾還是不回滾。如果不進行任何處理同樣數據會發生回滾。
例子2:
@Transactional(propagation
= Propagation.REQUIRED)
public void updateUserAgeById(int age, long id) {
userDao.updateUserInfoById(age, id);
commonService.updateUserExtById("未知", 1);
int b = 1/0;
//
如果出現運行時異常,此處會回滾 並對外拋出異常
@Transactional(propagation = Propagation.NESTED)
public void updateUserExtById(String address, long id) {
userDao.updateUserExtById(address, id);
//int a = 1/0;
}
異常發生在userservice方法中,因爲屬於嵌套事務,所以userservice和commonservice都會發生回滾。
例子3:
@Transactional(propagation = Propagation.REQUIRED)
public void updateUserAgeById(int age, long id) {
userDao.updateUserInfoById(age, id);
commonService.updateUserExtById("未知", 1);
//int b = 1/0;
// 如果出現運行時異常,此處會回滾 並對外拋出異常
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUserExtById(String address, long id) {
userDao.updateUserExtById(address, id);
int a = 1/0;
}
此處模擬的是commonservice使用的是Propagation.REQUIRES_NEW。userservice中的事務會被掛起。commonservice會新開一個事務。經過測試,此處模擬commonservice異常,其對應的事務會回滾。同樣此處會對外拋出異常,userservice視情況對異常處理,選擇回滾還是不回滾。
例子4:
@Transactional(propagation = Propagation.REQUIRED)
public void updateUserAgeById(int age, long id) {
userDao.updateUserInfoById(age, id);
commonService.updateUserExtById("未知", 1);
int b = 1/0;
// 如果出現運行時異常,此處會回滾 並對外拋出異常
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUserExtById(String address, long id) {
userDao.updateUserExtById(address, id);
//int a = 1/0;
}
例子5:
@Transactional(propagation = Propagation.REQUIRED)
public void updateUserAgeById(int age, long id) {
userDao.updateUserInfoById(age, id);
//commonService.updateUserExtById("未知", 1);
//int b = 1/0;
try {
commonService.updateUserExtById("未知", 1);
} catch (Exception e) {
// TODO: handle exception
}
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateUserExtById(String address, long id) {
userDao.updateUserExtById(address, id);
int a = 1/0;
}
最後再來看看同用Propagation.REQUIRED的情況。此處模擬commonservice異常,不用懷疑commonservice肯定會回滾。但是此處userservice進行了異常捕獲,userservice還會回滾嗎?答案是不會。因爲commonservice根本不會拋出異常。兩者用的是一個事務,commonservice發生異常,整個事務直接rollback。
好了,大概清楚了spring事務的傳播關係。網上有很多傳播的關係,但是都講的雲裏霧裏的。所以特此文章記錄一下。