<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你讀懂Spring的事務(wù)傳播行為

          共 17480字,需瀏覽 35分鐘

           ·

          2021-09-20 01:16

          今日推薦
          吊打 ThreadLocal,談?wù)凢astThreadLocal為啥能這么快?
          一個Github項目搞定微信、QQ、支付寶等第三方登錄
          注解+反射優(yōu)雅的實現(xiàn)Excel導(dǎo)入導(dǎo)出(通用版)
          Fluent Mybatis 牛逼!
          Nginx 常用配置清單
          這玩意比ThreadLocal叼多了,嚇得我趕緊分享出來。

          來源:blog.csdn.net/xuan_lu/article/details/106006755

          一、概念

          首先簡單了解一下Spring中事務(wù)傳播行為是什么?聽起來很高端,但是真正用起來的時候,稍有不慎,就會讓自己陷入困境之中,所以在使用之前,我們必須要十分耐心認真的學(xué)習(xí)它。

          從名字理解起來,事務(wù)傳播行為,既然為傳播就肯定發(fā)生在兩個實體之間,否則單個實體又如何發(fā)生行為呢。通俗點講就是“一個巴掌拍不響”。下面進入正規(guī)話題。

          事務(wù)傳播行為主要用來描述由某一個事務(wù)傳播行為修飾的方法被嵌套進另一個方法的事務(wù)中,該事務(wù)如何傳播。這個概述可能不好理解,換句話就是當一個事務(wù)方法被另一個事務(wù)方法調(diào)用時,這個事務(wù)方法應(yīng)該如何進行。

          下面用代碼+文字說明解釋上面的概念。

          @Transaction(Propagation=XXX)
          public void methodA(){
              methodB();
              //doSomething
           }
           
           @Transaction(Propagation=XXX)
           public void methodB(){
              //doSomething
           }

          methodA事務(wù)方法調(diào)用methodB事務(wù)方法時,methodB是繼續(xù)在調(diào)用者methodA的事務(wù)中運行呢,還是為自己開啟一個新事務(wù)運行,這就是由methodB的事務(wù)傳播行為決定的。

          注意:methodA和methodB都加了事務(wù)。methodA()也可以不用開啟事務(wù),某一個事務(wù)傳播行為修飾的方法并不是必須要在開啟事務(wù)的外圍方法中調(diào)用。

          二、Spring中七種事務(wù)傳播行為

          通過上面?zhèn)未a加文字解釋了解到事務(wù)傳播行為的相關(guān)概念,下面就要學(xué)習(xí)事務(wù)傳播行為的類型和運行機制。

          驗證

          Propagation_Required

          調(diào)用者方法不存在事務(wù)傳播行為

          1.調(diào)用者方法內(nèi)部存在異常時,被調(diào)用者方法均存在事務(wù),那么結(jié)果如何呢?

          @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
          public void insertStudent(StudentDo studentDo
          {
               studentMapper.insertStudent(studentDo);
               System.out.println("----------------------->Student插入成功!");
          }

          @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
             public void insertClass(ClassDo classDo
          {
                classMapper.insertClass(classDo);
                System.out.println("----------------------->Class插入成功!");
          }

          單元測試

          @SpringBootTest
          @RunWith(SpringRunner.class)
          public class PropagationTest {

              private final static StudentDo studentDo = new StudentDo();

              private final static ClassDo classDo = new ClassDo();
              static {
                  studentDo.setClassId(1);
                  studentDo.setStudentName("student1");
                  studentDo.setAddress("測試");

                  classDo.setClassName("class_1");
                  classDo.setClassNo("Class01");
              }
              @Autowired
              private StudentService studentService;

              @Autowired
              private ClassService classService;

              @Test
              public void insertTest() {
                  studentService.insertStudent(studentDo);
                  classService.insertClass(classDo);
                  
              }
          }

          結(jié)果:兩條數(shù)據(jù)均被插入數(shù)據(jù)庫。由于外部方法并沒有開啟事務(wù),所以內(nèi)部方法均在自己的事務(wù)提交或者回滾,因此外部方法中存在異常,內(nèi)部方法事務(wù)不會回滾。

          2.被調(diào)用者均存在事務(wù),而在被調(diào)用者中存在異常,那么結(jié)果如何?

          @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }

           //此方法中拋出異常
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertClassByException(ClassDo classDothrows CustomException 
          {
                  classMapper.insertClass(classDo);
                  throw new CustomException();
              }

          單元測試代碼

          private final static StudentDo studentDo = new StudentDo();
              private final static ClassDo classDo = new ClassDo();
              static {
                  studentDo.setClassId(2);
                  studentDo.setStudentName("student2");
                  studentDo.setAddress("測試2");

                  classDo.setClassName("class_2");
                  classDo.setClassNo("Class02");
              }
          @Test
              public void insertExceptionTest() throws CustomException {
                  studentService.insertStudent(studentDo);
                  classService.insertClassByException(classDo);
              }

          結(jié)果:第一數(shù)據(jù)成功插入,第二條數(shù)據(jù)因異常存在,事務(wù)回滾。內(nèi)部方法均在各個的事務(wù)中運行,class事務(wù)回滾,student數(shù)據(jù)不會受到影響。

          結(jié)合1和2我們可以得出結(jié)論

          1:通過這兩個方法我們證明了在外圍方法未開啟事務(wù)的情況下Propagation_Required修飾的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。

          2.調(diào)用者開啟事務(wù)傳播行為

          內(nèi)部方法同上

          //單元測試方法
           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertInnerExceptionThrowsTest() throws CustomException 
          {
                  studentService.insertStudent(studentDo);
                  classService.insertClassByException(classDo);
              }

          結(jié)果:內(nèi)部方法雖然存在事務(wù)傳播行為,但是外部方法也存在事務(wù)且使用Propagation.REQUIRED修飾,所有內(nèi)部方法不會新建事務(wù),直接運行在當前事務(wù)中,所以student、class均會被回滾。

          學(xué)習(xí)資料:Java進階視頻資源

          3.調(diào)用者開啟事務(wù)傳播行為,但是捕獲內(nèi)部方法異常

           /**
            * 內(nèi)部方法發(fā)生異常情況,外部方法即使捕獲處理該異常,依然數(shù)據(jù)會被回滾
            */

          @Test
          @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
          public void insertInnerExceptionTest() 
          {
              studentService.insertStudent(studentDo);
              try {
                  classService.insertClassByException(classDo);
              } catch (CustomException e) {
                  e.printStackTrace();
              }
          }

          結(jié)果:外圍方法開啟事務(wù),內(nèi)部方法加入外圍方法事務(wù),內(nèi)部方法拋出異?;貪L,即使方法被catch不被外圍方法感知,整個事務(wù)依然回滾。同2一樣,調(diào)用者方法執(zhí)行操作和被調(diào)用者中的方法操作結(jié)果均被回滾。

          Propagation_Supports

           @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }

           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertSupportsTest() 
          {
                  studentService.insertStudent(studentDo);
              }

          解釋:如果單純的調(diào)用insertStudent()方法,則以非事務(wù)執(zhí)行,即使后面存在異常情況,執(zhí)行操作結(jié)果不會觸發(fā)事務(wù)回滾機制。當調(diào)用insertSupportsTest()方法時,該方法以REQUIRED修飾,則會新建一個事務(wù),內(nèi)部調(diào)用insertStudent()方法,所以insertStudent()會加入到當前事務(wù)中執(zhí)行。

          Propagation_Mandatory

          @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }

           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertSupportsTest() 
          {
                  studentService.insertStudent(studentDo);
              }

          解釋結(jié)果:MANDATORY表示被修飾的方法必須在事務(wù)中運行。當單獨調(diào)用insertStudent時,因為當前沒有一個活動的事務(wù),則會拋出異常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);當調(diào)用insertSupportsTest時,insertStudent則加入到insertSupportsTest的事務(wù)中,事務(wù)地執(zhí)行。

          Propagation_Required_New

          表示被修飾的方法必須運行在它自己的事務(wù)中。一個新的事務(wù)會被啟動。如果調(diào)用者存在當前事務(wù),則在該方法執(zhí)行期間,當前事務(wù)會被掛起。

          private final static StudentDo studentDo = new StudentDo();
          private final static ClassDo classDo = new ClassDo();
              static {
                  studentDo.setClassId(2);
                  studentDo.setStudentName("requireNew");
                  studentDo.setAddress("requireNew");
              }
           @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }
              @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
              public void insertClassByException(ClassDo classDothrows CustomException 
          {
                  classMapper.insertClass(classDo);
                  throw new CustomException();
              }
              
           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertInnerExceptionTest() 
          {
                  studentService.insertStudent(studentDo);
                  try {
                      classService.insertClassByException(classDo);
                  } catch (CustomException e) {
                      e.printStackTrace();
                  }
              }

          結(jié)果解析:insertStudent(),insertClassByException()方法執(zhí)行時,外部方法事務(wù)被掛起,內(nèi)部方法會新建事務(wù),直至該方法執(zhí)行結(jié)束,恢復(fù)外部方法事務(wù)執(zhí)行。兩者之間事務(wù)存在隔離性,insertClassByException()方法遇到異常,觸發(fā)事務(wù)回滾機制,但insertStudent()執(zhí)行結(jié)果并受到影響。學(xué)習(xí)資料:Java進階視頻資源

          如圖所示:

          Propagation_Not_Supported

          表示被修飾的方法不應(yīng)該運行在事務(wù)中。如果調(diào)用者存在當前事務(wù),則該方法運行期間,當前事務(wù)將被掛起。

           private final static ClassDo classDo = new ClassDo();
              static {

                  classDo.setClassName("notSupport");
                  classDo.setClassNo("notSupport");
              }
           @Transactional(propagation = Propagation.NOT_SUPPORTED, rollbackFor = Exception.class)
              public void insertClassByException(ClassDo classDothrows CustomException 
          {
                  classMapper.insertClass(classDo);
                  throw new CustomException();
              }
           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertInnerExceptionTest() 
          {
                  try {
                      classService.insertClassByException(classDo);
                  } catch (CustomException e) {
                      e.printStackTrace();
                  }
              }

          結(jié)果解釋:即使外部方法開啟事務(wù),但是insertClassByException()執(zhí)行,當前事務(wù)會掛起,not_support以非事務(wù)方式運行,所以即使遇到異常情況,執(zhí)行結(jié)果也不會觸發(fā)回滾。

          Propagation_Never

          表示被修飾的方法不應(yīng)該運行事務(wù)上下文中。如果調(diào)用者或者該方法中存在一個事務(wù)正在運行,則會拋出異常。

           @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }

           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertInnerExceptionTest() 
          {
                  studentService.insertStudent(studentDo);
              }

          結(jié)果如圖:

          Propagation_Nested

          • 表示當前方法已經(jīng)存在一個事務(wù),那么該方法將會在嵌套事務(wù)中運行。
          • 嵌套的事務(wù)可以獨立與當前事務(wù)進行單獨地提交或者回滾。
          • 如果當前事務(wù)不存在,那么其行為與Propagation_Required一樣。
          • 嵌套事務(wù)的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)。外層事務(wù)失敗時,會回滾內(nèi)層事務(wù)所做的動作。而內(nèi)層事務(wù)操作失敗并不會引起外層事務(wù)的回滾。

          1.外部未開啟事務(wù)時,內(nèi)部方法則新建事務(wù)執(zhí)行

           private final static StudentDo studentDo = new StudentDo();
              private final static ClassDo classDo = new ClassDo();
              static {
                  studentDo.setClassId(2);
                  studentDo.setStudentName("NESTED");
                  studentDo.setAddress("NESTED");

                  classDo.setClassName("NESTED");
                  classDo.setClassNo("NESTED");
              }
           @Test
              public void insertTest() {
                  studentService.insertStudent(studentDo);
                  classService.insertClass(classDo);
                  throw new RuntimeException();

              }
          @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
              public void insertStudent(StudentDo studentDo
          {
                  studentMapper.insertStudent(studentDo);
                  System.out.println("----------------------->Student插入成功!");
              }
          @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
              public void insertClass(ClassDo classDo
          {
                  classMapper.insertClass(classDo);
                  System.out.println("----------------------->Class插入成功!");
              }

          結(jié)果:

          2.外部方法開啟事務(wù):

          • 如果外部方法發(fā)生異常,則內(nèi)部事務(wù)一起發(fā)生回滾操作;
          • 如果外部無異常情況,內(nèi)部被調(diào)用方法存在異常情況,則內(nèi)部方法獨立回滾(疑問點???我用以下實例驗證,但是外部方法也一樣被回滾了,請各位大佬給與解答);
          //單測代碼
           private final static StudentDo studentDo = new StudentDo();
              private final static ClassDo classDo = new ClassDo();
              static {
                  studentDo.setClassId(2);
                  studentDo.setStudentName("NESTED_InnerException");
                  studentDo.setAddress("NESTED_InnerException");

                  classDo.setClassName("NESTED_InnerException");
                  classDo.setClassNo("NESTED_InnerException");
              }
           @Test
              @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
              public void insertInnerExceptionThrowsTest() throws CustomException 
          {
                  studentMapper.insertStudent(studentDo);
                  classService.insertClassByException(classDo);
              }
          //NESTED事務(wù)傳播行為
           @Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)
              public void insertClassByException(ClassDo classDothrows CustomException 
          {
                  classMapper.insertClass(classDo);
                  throw new RuntimeException();
              }

          源代碼傳送門:

          https://github.com/stream-source/stream-source/tree/master/informal-essay/src/test/java/com/qxy

          推薦一些很不錯的計算機學(xué)習(xí)教程,包括:數(shù)據(jù)結(jié)構(gòu)、算法、計算機網(wǎng)絡(luò)、操作系統(tǒng)、Java(spring、springmvc、springboot、springcloud等)等等 ,全部收集于網(wǎng)絡(luò),如果有侵權(quán),請聯(lián)系刪除!
          下面是部分截圖:
          獲取方式

          點擊下方公眾號,回復(fù):好好學(xué)Java,即可獲取。
          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人Av音影 | 亚洲AV无码久久精品色欲 | xx在线看 | 在线观看免费黄色 | 约操魔都极品细腰 |