Spring事務管理中關於傳播行爲的學習總結

具體上次寫事務管理這塊內容已經過去好幾個月了,昨天打了個草稿,這次學習事務管理相當於是複習,也相當於是鞏固這個知識點。關於事務和緩存,在Spring中都有專門的管理機制,當下的開發趨勢中,關於Annotation的表達方式越來越常用,之前的事務管理文章中所舉例是採用了配置文件的方式,這次就採用註解的方式來鞏固下Spring事務管理的傳播行爲吧。

事務管理:https://blog.csdn.net/Nerver_77/article/details/79876040

Spring中的事務管理:https://blog.csdn.net/Nerver_77/article/details/79896351

以上兩篇是以往所總結的內容,這篇就不贅述,直接開始正題:事務管理中的傳播行爲!

當事務方法被另一個事務方法所調用時,須指定事務應該如何傳播。

這裏將搭建一個測試事務傳播行爲的測試用例,在此之前,先搭建所需要的環境。

1. 建立測試數據表:test

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

2. Dao層搭建:Mybatis-plus代碼生成器

關於Mybatis-plus的代碼生成器詳情可見文檔:http://mp.baomidou.com/#/generate-code

類比Mybatis的逆向工程,都是用來生成Dao層代碼的,Mybatis-plus基於的BaseMapper,實現了基本的CURD操作的封裝,我們只需要生成代碼即可,無需更改。當然如果有其他複雜查詢需要自定義。

針對test表,生成對應的pojo對象:Test.java,Dao接口:TestMapper.java,mapping文件:TestMapper.xml

生成的Dao接口,繼承了BaseMapper,基本的CURD都有的,這裏測試用例無需複雜查詢,這裏就不寫了。

public interface TestMapper extends BaseMapper<Test> {

}

3. Service層搭建:接口 + 實現類方式

接口:這樣相同的接口設立了三個,改個名字就好。

public interface TestService1 {
    void test1();
}

實現類: Test1的實現類如下,Test2、Test3的實現類一樣。

@Service
public class TestServiceImpl1 implements TestService1{

    @Autowired
    private TestMapper testMapper;

    @Autowired
    private TestService2 testService2;

    @Autowired
    private TestService3 testService3;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    public void test1() {

        Test test1 = new Test();
        test1.setValue("test1事務測試");
        testMapper.insert(test1);

        try {
            testService2.test2();
        } catch (Exception e) {
            System.err.println("test2有異常");
            e.printStackTrace();
        }

        testService3.test3();
    }
}
@Service
public class TestServiceImpl2 implements TestService2{

    @Autowired
    private TestMapper testMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void test2() {
        Test test2 = new Test();
        test2.setValue("test2事務測試");
        testMapper.insert(test2);
//        int i = 1/0;
    }
}

這裏需要說明下:實現類中的方法都是調用testMapper進行數據添加,test1方法中嵌套了test2、test3的數據添加業務。牽扯到事務的傳播行爲,必須要存在事務方法的嵌套,我們在下述進行傳播行爲測試的時候,先採用test1和test2。

採用Junit創建測試類:test1爲測試入口。

public class TransactionTest extends BaseJunit {

    @Autowired
    private TestService1 testService1;

    @Test
    public void test(){
        testService1.test1();
    }

}

4. 開啓測試:下面會根據事務的每個傳播行爲進行測試。

提示:自制異常:1/0 /by zero ,事務掛起:當前事務中的方法也是處於執行狀態 , pass:控制檯結果正確,這裏不重複上圖。

方法開啓事務:採用 @Transactional註解方式聲明。@Transactional(propagation = Propagation.REQUIRED)

詳細的註解聲明問題在第一個測試中進行詳細介紹,後面的測試大同小異,就是更改propagation參數而已。

以下傳播行爲的測試默認都採用test1、test2,只有PROPAGATION_NESTED時候會使用test3。

 PROPAGATION_REQUIRED--表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啓動一個新的事務
            test1:propagation = Propagation.REQUIRED

           
            test2:propagation = Propagation.REQUIRED

            
            測試:對test1而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,會正常執行。
            數據庫結果:test1事務測試 + test2事務測試(ID字段自增長,無需在意)

            
            控制檯結果:pass

         

            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.REQUIRED + 自制異常
            測試:對test1而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,但是test2中存在異常,基於事務1的一致性,事務1會進行回滾。
            數據庫結果:無記錄
            控制檯結果:出現異常,事務1中的方法執行結果回滾。


       

PROPAGATION_SUPPORTS--表示當前方法不需要事務,但是如果存在當前事務的話,那麼該方法會在這個事務中運行,如果當前沒有事務,就以非事務方式執行。 
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.SUPPORTS
            測試:對test1而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,會正常執行。
            數據庫結果:test1事務測試 + test2事務測試
            控制檯結果:pass
            上述情況即:test1、test2都在事務1中執行,任何一方法出現異常就會導致事務回滾。

            test1:未開啓事務
            test2:propagation = Propagation.SUPPORTS + 自制異常
            測試:對test2而言,當前方法沒有運行事務中,因此test2將以非事務方式執行(遇到異常也不會進行回滾)。
            數據庫結果:test1事務測試 + test2事務測試
            控制檯結果:test1未處於事務中,正常執行,test2中聲明瞭SUPPORTS並自制異常,非事務方式執行方法,出現異常也不會回滾。

PROPAGATION_MANDATORY--表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常。
            test1:未開啓事務
            test2:propagation = Propagation.MANDATORY
            測試:對test2而言沒有處於事務中,會拋出異常。
            數據庫結果:test1事務測試
            控制檯結果:MANDATORY所聲明的事務中爲發現事務存在,即外圍無事務存在。 當test2外圍存在事務時,就會事務執行成功。


           

PROPAGATION_REQUIRES_NEW--表示當前方法必須運行在它自己的事務中。一個新的事務將被啓動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。 
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.REQUIRED_NEW + 自制異常
            測試:對test1而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,但是test2會重新開啓一個新事務2,此時事務1和事務2互不影響。
            數據庫結果:test1事務測試
            控制檯結果:test1正常 test2回滾

       

PROPAGATION_NOT_SUPPORTED--表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。 
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.REQUIRED + 自制異常
            測試:對test1而言,當前方法運行在事務1中。對test2而言,當前所處與事務1中,但是test2不應該運行在事務中,也就是test2獨立出事務1,以非事務方式運行,此時事務1掛起(不影響方法執行),。
            數據庫結果:test1事務測試 + test2事務測試
            控制檯結果:test2獨立出事務以非事務方式運行。出現異常也不會回滾。

       

PROPAGATION_NEVER--表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.NEVER
            測試:對test1而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1中,存在事務運行,拋出異常。
            數據庫結果:test1事務測試
            控制檯結果:NEVER 表明發現外圍存在事務運行,拋出異常。

            test1:未開啓事務
            test2:propagation = Propagation.NEVER
            測試:對test2而言不存在事務運行,可以正常執行。
            數據庫結果:test1事務測試 + test2事務測試
            控制檯結果:pass

PROPAGATION_NESTED--一個事務內部嵌套事務的執行不會影響外部事務,但外部事務的執行要影響內部
            一個事務內部嵌套事務的執行不會影響外部事務:REQUIRES_NEW,開啓全新事務,獨立外圍事務運行。    
            外部事務的執行要影響內部:REQUIRED,外圍事務影響內部方法。
            需要把這兩者需求結合起來:
            1.外部事物影響內部事務
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.NESTED
            test3:propagation = Propagation.REQUIRED + 自制異常
          測試:對test1、test3而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,並聲明傳播方式爲NESTED,外部事物出現異常,此時事務1會回滾。
            數據庫結果:無記錄
            控制檯結果:test3出現異常,由於外部事物影響內部,所以test1、test2、test3方法均回滾。


            2.內部事務不影響外部事物
            test1:propagation = Propagation.REQUIRED
            test2:propagation = Propagation.NESTED + 自制異常
            test3:propagation = Propagation.REQUIRED
            測試:對test1、test3而言,當前方法運行在事務1中,對test2而言當前事務運行在事務1內部,並聲明傳播方式爲NESTED,test2構建的內部事務出現異常,不影響外部事務。
            數據庫結果:test1事務測試 + test3事務測試
            控制檯結果:內部事務不影響外部事物,外部事務1正常執行,內部事務出現異常,方法觸發回滾。

至此,關於Spring事務管理的傳播行爲的測試完結,瞭解事務傳播行爲可以合理安排業務執行。基於註解方式聲明事務這一操作,實質上基於Spring AOP的動態代理機制,相對底層的學習會在以後展開,需要學習的小夥伴可以參考之前兩篇文章對概念性進行理解,結合測試用例,有利於理解和學習。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章