Spring 事務管理 事務的傳播級別
阿新 • • 發佈:2018-12-25
例子:對於預設的傳播級別 REQUIRED 的測試
首先對於 REQUIRED 的解釋如下: 預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務,也就是大家都使用同一個事務模型,只要有一個發生了異常,那麼整個事務都會回滾。
其中對於發生異常導致事務回滾需要注重理解,否則對於REQUIRES_NEW 就會認為某些行為與預先的不一樣。
下面針對 REQUIRES_NEW 的測試如下:
@Service public class A { @Resource private PersonMapper personMapper; @Resource private B b; @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void save() { personMapper.insert(Person.builder().name("A").age(12).build()); b.save(); } }
@Service public class B { @Resource private PersonMapper personMapper; @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void save() { personMapper.insert(Person.builder().name("B").age(12).build()); throw new RuntimeException(); } }
@GetMapping(value = "/get2")
public Object get2() {
a.save();
return "success";
}
由於最開始對於異常回滾理解錯誤,認為在呼叫A的save()方法時,建立一個事務,這時再在 呼叫 b的save() 由於傳播級別是建立新的事務,所以B丟擲異常,應該僅僅會導致B的儲存失敗,但是實際測試卻發現,A,B的儲存都失敗了,經過仔細的思考,認為,事務重新建立應該是沒有問題的,可能是對於異常回滾的理解錯誤導致的。
於是修改了A 如下:
@Service public class A { @Resource private PersonMapper personMapper; @Resource private B b; @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void save() { personMapper.insert(Person.builder().name("A").age(12).build()); try{ b.save(); }catch (Exception e){ } } }
經過測試,發現此時就是 B儲存失敗而A儲存成功了,經過測試推論如下:
在A物件中沒有追加try catch的時候,當B 丟擲異常的時候,B的事務回滾,但是由於並沒有對該異常進行處理,於是該異常擴散到了A中的呼叫點(b.save();)由於此處的異常,因而導致A回滾了,當追加 try catch 之後 此異常就不會導致A回滾了。
為了驗證此猜想,編寫如下測試用例:
@Service
public class A {
@Resource
private PersonMapper personMapper;
@Resource
private B b;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save() {
personMapper.insert(Person.builder().name("A").age(12).build());
try{
b.save();
}catch (Exception e){
}
}
}
@Service
public class B {
@Resource
private PersonMapper personMapper;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void save() {
personMapper.insert(Person.builder().name("B").age(12).build());
throw new RuntimeException();
}
}
在進行測試,就發現事務回滾了,表明B中的異常導致了整個事務的回滾。下面繼續測試巢狀事務 NESTED :巢狀事務 類似於後一個事務為第一個事務的子事務
經過測試規則如下:父事務回滾,子事務一定回滾,但是子事務回滾,不影響父事務回滾。
PROPAGATION_SUPPORTS:如果沒有,就以非事務方式執行;如果有,就使用當前事務。
以下的事務就比較容易理解了:
PROPAGATION_NOT_SUPPORTED:如果沒有,就以非事務方式執行;如果有,就將當前事務掛起。即無論如何不支援事務。
PROPAGATION_NEVER:如果沒有,就以非事務方式執行;如果有,就丟擲異常。
PROPAGATION_MANDATORY:如果沒有,就丟擲異常;如果有,就使用當前事務。