<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>

          What?天天用Spring你竟然不知道事務(wù)的傳播性?

          共 11247字,需瀏覽 23分鐘

           ·

          2021-08-23 17:20

          點(diǎn)擊下方“IT牧場”,選擇“設(shè)為星標(biāo)”

          在我們?nèi)粘5拈_發(fā)中Spring是必備的技能,在面試的時候,這一塊的知識也會著重地問,雖然每天都在使用,但是稍不注意就會出問題,今天這篇文章我們來詳細(xì)的聊聊Spring的事務(wù)傳播性,助力金三銀四面試季。

          什么是Spring事務(wù)傳播性?Spring事務(wù)傳播性是當(dāng)多個包含事務(wù)的方法嵌套調(diào)用的時候,處理事務(wù)的規(guī)則。例如:兩個事務(wù)方法A、B,當(dāng)方法A調(diào)用方法B的時候,方法B是合并到方法A的事務(wù)中還是開啟一個新的事務(wù)。如果是合并到方法A的事務(wù)中,那么當(dāng)方法B回滾之后,方法A會不會回滾等等。Spring有幾種處理這種嵌套事務(wù)的方式?通過源碼我們發(fā)現(xiàn)有7種,定義在Propagation這個枚舉類中,接下來我們講詳細(xì)說一下每一種傳播行為都可以幫助我們處理什么樣的問題。

          1、Propagation.REQUIRED

          這種傳播行為是Spring默認(rèn)的,當(dāng)我們使用@Transactional注解且不指定傳播行為的時候就是使用這個,它指的是外層的調(diào)用方法如果開啟了事務(wù),那么當(dāng)前方法就合并到外層的事務(wù)中執(zhí)行,如果外層調(diào)用方法沒有開啟事務(wù),就開啟一個事務(wù)執(zhí)行當(dāng)前方法。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
              
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  serviceB.methodB();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          我們的實(shí)例代碼,服務(wù)A的methodA方法調(diào)用了服務(wù)B的methodB方法,并且我們給methodA通過注解@Transactional加了一個事務(wù),并定義了傳播性為REQUIRED。

          methodA本身開啟了事務(wù),methodB也開啟了事務(wù),且事務(wù)的傳播性為REQUIRED,所以當(dāng)methodA調(diào)用methodB的時候,methodB會合并到methodA開啟的事務(wù)中執(zhí)行。這個時候兩個方法是在一個事務(wù)中執(zhí)行的,當(dāng)兩個方法都執(zhí)行成功后提交事務(wù)。

          這個地方很多人就會犯迷糊啦,如果methodB在執(zhí)行過程中拋出了異常,那么methodB會回滾,那么methodA執(zhí)行的操作會回滾嗎?這里其實(shí)只要記住一點(diǎn),這兩個操作是在同一個事務(wù)中,事務(wù)是原子性操作的,所以methodA也會回滾。

          面試的時候還會進(jìn)一步挖坑!如果methodA中使用try-catch捕獲了異常,那么methodA執(zhí)行的操作還會回滾嗎?

          這里還是要牢記事務(wù)本身具有原子性,所以無論有沒有catch異常,都會回滾的。

          2、Propagation.SUPPORTED

          這個傳播行為是說,如果當(dāng)前方法的調(diào)用方開啟了事務(wù),那么當(dāng)前方法就合并到外層事務(wù)中執(zhí)行,如果外層事務(wù)沒有開啟事務(wù),那么當(dāng)前方法也不會創(chuàng)建事務(wù),就不開啟事務(wù)執(zhí)行。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;

              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  serviceB.methodB();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.SUPPORTED)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          我們看到,methodB開啟了事務(wù),傳播性為SUPPORTED,methodA沒有開啟事務(wù),那么methodA執(zhí)行的時候不會開啟事務(wù),在調(diào)用methodB的時候,由于methodB開啟了事務(wù),但傳播性為SUPPORTED,所以methodB也不會開啟事務(wù),以非事務(wù)的方式運(yùn)行。

          如果methodA開啟了事務(wù),那么methodB會合并到methodA的事務(wù)中執(zhí)行。

          3、Propagation.MANDATORY

          這個傳播行為是指,傳播性為MANDATORY的方法只能被開啟事務(wù)的方法調(diào)用,如果調(diào)用方?jīng)]有開啟事務(wù)就會拋出異常。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;

              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  serviceB.methodB();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.MANDATORY)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          我們的示例中,methodA沒有開啟事務(wù),調(diào)用了開啟事務(wù)并且傳播性為MANDATORY的methodB,這時,執(zhí)行methodA的業(yè)務(wù)操作時不開啟事務(wù),在調(diào)用服務(wù)B的methodB方法的時候,就會拋出異常:

          IllegalTransactionStateException(
                              "No existing transaction found for transaction marked with propagation 'mandatory'")

          4、Propagation.REQUIRES_NEW

          這個傳播行為是指,每次都會開啟一個新的事務(wù)來執(zhí)行當(dāng)前方法。比如調(diào)用放methodA開啟了事務(wù),在methodA中調(diào)用開啟了事務(wù)且傳播性為REQUIRES_NEW的方法methodB,那么在methodA會開啟一個事務(wù)執(zhí)行自己的業(yè)務(wù)代碼,在調(diào)用methodB的時候的時候會先掛起methodA的事務(wù),然后開啟一個新的事務(wù)執(zhí)行methodB,在methodB的事務(wù)提交后,會恢復(fù)methodA的事務(wù)繼續(xù)執(zhí)行。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
           @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  try{
                      serviceB.methodB();
                  } catch (Exception e){
                      
                  }
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRES_NEW)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          我們的實(shí)例代碼中,methodA開啟了事務(wù),傳播性為REQUIRED,所以在執(zhí)行的時候,methodA會開啟一個事務(wù)A,然后執(zhí)行methodA的業(yè)務(wù),在調(diào)用methodB的時候,由于methodB開啟了事務(wù),且事務(wù)傳播性為REQUIRES_NEW,,所以這個時候就先掛起事務(wù)A,重新開啟一個事務(wù)B來執(zhí)行methodB,在methodB執(zhí)行完提交事務(wù)后,會恢復(fù)事務(wù)A的執(zhí)行,最后再提交事務(wù)A。

          這個地方面試的時候可能會問到,methodB在執(zhí)行的過程中出現(xiàn)了異常整個過程會發(fā)生什么變化?

          我們根據(jù)上邊的調(diào)用圖分析,在methodB執(zhí)行過程中拋出異常,事務(wù)B會回滾,如果methodA中調(diào)用methodB的時候catch住了異常,并沒有向外排除,那么methodA不會回滾,如果methodA中沒有處理異常,那么methodA也會回滾。

          5、Propagation.NOT_SUPPORTED

          這個傳播性就是不支持事務(wù),如果調(diào)用方開啟了事務(wù),那么在執(zhí)行的時候會先掛起調(diào)用方的事務(wù),以非事務(wù)的方式執(zhí)行當(dāng)前的業(yè)務(wù),在執(zhí)行完之后,再恢復(fù)調(diào)用方的事務(wù)繼續(xù)執(zhí)行。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
           @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  serviceB.methodB();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.NOT_SUPPORTED)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          在我們的實(shí)例代碼中,methodA開啟了事務(wù),傳播性為REQUIRED,methodB的傳播性為NOT_SUPPORTED,在執(zhí)行的過程中,methodA會開啟一個事務(wù)A,在調(diào)用methodB的時候,會先掛起methodA的事務(wù)A,然后以非事務(wù)的方式執(zhí)行methodB的業(yè)務(wù),在methodB執(zhí)行完之后,恢復(fù)事務(wù)A,最后提交事務(wù)A。整個過程如下圖:

          6、Propagation.NEVER

          這個傳播性和前一種傳播性都是不支持事務(wù),但是不同的是這種傳播性是調(diào)用方如果開啟了事務(wù),那么在執(zhí)行當(dāng)前方法的時候就會拋出異常。下邊還是通過一個示例來看:

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
           @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //調(diào)用服務(wù)B的methodB方法
                  serviceB.methodB();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.NEVER)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          示例中我們看到,methodA開啟了事務(wù),傳播性為REQUIRED,methodB的傳播性為NEVER,那么在methodA調(diào)用methodB的時候,就會拋出如下異常:

          IllegalTransactionStateException(
                              "Existing transaction found for transaction marked with propagation 'never'")

          7、Propagation.NESTED

          這個傳播性和REQUIRED很相似,都是當(dāng)調(diào)用方?jīng)]有開啟事務(wù)時,就開啟一個新的事務(wù),如果調(diào)用方開啟了事務(wù)就合并到調(diào)用方的事務(wù)中執(zhí)行,不同的地方就是NESTED這種傳播行為可以保存狀態(tài)點(diǎn),當(dāng)事務(wù)回滾的時候,可以回滾到某一個地方,從而避免了嵌套事務(wù)全部回滾的情況。

          //服務(wù)A
          @Service
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
           @Transactional(rollbackFor = Exception.classpropagation = Propagation.REQUIRED)
              public void methodA() {
                  //methodA 的業(yè)務(wù)操作
                  System.out.println("methodA執(zhí)行業(yè)務(wù)");
                  //
                  try{
                      serviceB.methodB();
                  }catch(Exception e) {
                      
                  }
                  //methodA在methodB之后的業(yè)務(wù)操作...
                  update();
              }
          }

          //服務(wù)B
          @Service
          public class ServiceB {
              @Transactional(rollbackFor = Exception.classpropagation = Propagation.NESTED)
              public void methodB() {
                  System.out.println("methodB執(zhí)行業(yè)務(wù)");
              }
          }

          在這個示例中,我們可以看到,在methodA執(zhí)行的時候,如果沒有開啟事務(wù),會先開啟一個事務(wù),然后執(zhí)行methodA的業(yè)務(wù)操作;在實(shí)行調(diào)用服務(wù)B的methodB的時候,由于其傳播行為NESTED,所以會創(chuàng)建一個savepoint,用于標(biāo)記methodA執(zhí)行的業(yè)務(wù)操作。

          然后methodB的業(yè)務(wù)操作是在methodA的事務(wù)中進(jìn)行的,當(dāng)methodB拋出異常時,methodB中的業(yè)務(wù)操作會回滾掉,methodA執(zhí)行的業(yè)務(wù)操作并不會回滾,因?yàn)樵趫?zhí)行methodB之前創(chuàng)建了savepoint,methodB只會回滾到這個savepoint點(diǎn)之前。

          這個地方注意的是,methodB回滾以后,對于methodA在methodB之后的業(yè)務(wù)操作是會被提交的,并不受methodB回滾的影響。

          最后

          我們常用的事務(wù)傳播行為其實(shí)只有兩種,分別是REQUIRED和REQUIRED_NEW。其余五種傳播行為只需要了解即可,可以在面試的時候展示一下知識面。

          干貨分享

          最近將個人學(xué)習(xí)筆記整理成冊,使用PDF分享。關(guān)注我,回復(fù)如下代碼,即可獲得百度盤地址,無套路領(lǐng)?。?/p>

          ?001:《Java并發(fā)與高并發(fā)解決方案》學(xué)習(xí)筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學(xué)習(xí)筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領(lǐng)域驅(qū)動設(shè)計(jì)速成)》?007:全部?008:加技術(shù)群討論

          加個關(guān)注不迷路

          喜歡就點(diǎn)個"在看"唄^_^

          瀏覽 61
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  国产激情在线视频网站 | 国产女人叫床高潮大片免费 | 成人无码片黄网站A毛片免费 | 99久久人妻无码中文字幕系列 | 中文字幕三级片在线观看 |