1. 程式人生 > >Spring 事務管理 事務的傳播級別

Spring 事務管理 事務的傳播級別

例子:對於預設的傳播級別 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:如果沒有,就丟擲異常;如果有,就使用當前事務。