spring 事務傳播性
一.什麼是事務傳播性
大白話講就是,方法之間互相呼叫的時候,事務如何傳播,比如A()呼叫B(),B()的事務是和A()共用一個事務(失敗一起提交)?
還是新事務(兩者事務互不影響)?,還是說B()不需要事務?,這就是事務傳播性的意思。
@Transactional()
public void methodA(){
methodB();
//doSomething
}
@Transactional()
public void methodB(){
//doSomething
}
程式碼中的methodB()預設的傳播性是REQUIRED,表示和methodA共用一個事務,要提交一起提交,要失敗一起回滾。
二.spring中幾種事務傳播性
事務傳播性 | 說明 |
REQUIRED | 預設傳播性,如果當前有事務,就沿用當前事務,如果沒有就新建一個事務 |
SUPPORTS | 支援當前事務,如果當前沒有事務,就以非事務執行 |
REQUIRES_NEW | 新建一個事務,如果當前存在事務,就把當前事務掛起 |
NOT_SUPPORTED | 不支援事務,如果當前存在事務,就把當前事務掛起。 |
MANDATORY | 強制使用當前事務,如果當前沒有事務就拋異常 |
NEVER | 以非事務方式執行,如果當前存在事務,則丟擲異常 |
NESTED | 如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
三.舉例說明
1.REQUIRED
說明:支援當前事務,如果當前沒有事務就新建一個事務
insertUser()和insertStu是共用一個事務,要提交一起提交要失敗一起失敗。
@Transactional(propagation = Propagation.REQUIRED) public void insertUser(String name) { User user = new User(); user.setName(name); userDao.insertUser(user); stuService.insertStu(name); } stuService中 @Transactional(propagation = Propagation.REQUIRED) public void insertStu(String name){ Stu stu = new Stu(); stu.setName(name); stuDao.insertUser(stu); //這個地方發生異常,會引起insertStu也回滾,說明兩者的事務是同一個 throw new RuntimeException(); }
2.REQUIRES_NEW
說明:開啟新的事務,如果當前存在事務,就掛起當前事務。
insertUser()的失敗回滾,不會導致insertStu的回滾,因為insertStu()在一個新的事務中。
@Transactional(propagation = Propagation.REQUIRED)
public void insertUser(String name) {
User user = new User();
user.setName(name);
userDao.insertUser(user);
stuService.insertStu(name);
throw new RuntimeException();
}
//上面的方法拋異常事務的回滾,不會導致下面事務回滾,stu插入成功,user插入失敗
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertStu(String name){
Stu stu = new Stu();
stu.setName(name);
stuDao.insertUser(stu);
}
3.SUPPORTS
說明:如果當前已經存在事務,那麼加入該事務,否則建立一個所謂的空事務(可以認為無事務執行)
insertUser是以非事務執行的,所以insertStu也是沒有事務的,所以兩個儲存都會成功
但是如果給inertStu加上@Transactional(propagation = Propagation.REQUIRED)insertStu是有事務的。
public void insertUser(String name) {
User user = new User();
user.setName(name);
userDao.insertUser(user);
stuService.insertStu(name);
throw new RuntimeException();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void insertStu(String name){
Stu stu = new Stu();
stu.setName(name);
stuDao.insertUser(stu);
}
4.NOT_SUPPORTED
說明:不支援事務,如果當前存在事務,掛起當前事務,然後新的方法在沒有事務的環境中執行
下面的insertUser會回滾,insertStu將以非事務執行,所以不會回滾
這種的業務場景可能是,日誌寫入事務要和主事務隔離,外層事務寫入失敗,不影響日誌的寫入。
@Transactional(propagation = Propagation.REQUIRED)
public void insertUser(String name) {
User user = new User();
user.setName(name);
userDao.insertUser(user);
stuService.insertStu(name);
throw new RuntimeException();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void insertStu(String name){
Stu stu = new Stu();
stu.setName(name);
stuDao.insertUser(stu);
}
5.MANDATORY
說明:當前必須存在一個事務,否則丟擲異常。
因為insertUser()沒有配置事務,所以insertStu()會報錯。
異常資訊:No existing transaction found for transaction marked with propagation 'mandatory'
public void insertUser(String name) {
User user = new User();
user.setName(name);
userDao.insertUser(user);
stuService.insertStu(name);
throw new RuntimeException();
}
@Transactional(propagation = Propagation.MANDATORY)
public void insertStu(String name){
Stu stu = new Stu();
stu.setName(name);
stuDao.insertUser(stu);
}
6.NEVER
說明:不支援事務,如果當前存在事務,就丟擲異常。
因為insertUser()配置了事務,所以在insertStu中會報錯。
異常資訊:Existing transaction found for transaction marked with propagation 'never'
@Transactional(propagation = Propagation.REQUIRED)
public void insertUser(String name) {
User user = new User();
user.setName(name);
userDao.insertUser(user);
stuService.insertStu(name);
//throw new RuntimeException();
}
@Transactional(propagation = Propagation.NEVER)
public void insertStu(String name){
Stu stu = new Stu();
stu.setName(name);
stuDao.insertUser(stu);
}
7.NESTED
說明:NESTED修飾的內部方法屬於外部事務的子事務,外圍主事務回滾,子事務一定回滾,而內部子事務可以單獨回滾而不影響外圍主事務和其他子事務
主要的場景可能是,下單的時候,送積分,如果下單失敗,送積分也要回滾,但送積分失敗不影響下單失敗。這種場景可以使用這種傳播性