<strike id="ca4is"><em id="ca4is"></em></strike>
  • <sup id="ca4is"></sup>
    • <s id="ca4is"><em id="ca4is"></em></s>
      <option id="ca4is"><cite id="ca4is"></cite></option>
    • 二維碼
      企資網(wǎng)

      掃一掃關(guān)注

      當(dāng)前位置: 首頁(yè) » 企資快訊 » 匯總 » 正文

      Spring事務(wù)傳播講解透徹的深度好文

      放大字體  縮小字體 發(fā)布日期:2021-08-22 01:03:23    作者:史舒文    瀏覽次數(shù):27
      導(dǎo)讀

      事務(wù)傳播七種事務(wù)傳播行為詳解與示例在介紹七種事務(wù)傳播行為前,我們先設(shè)計(jì)一個(gè)場(chǎng)景,幫助大家理解,場(chǎng)景描述如下現(xiàn)有兩個(gè)方法A和B,方法A執(zhí)行會(huì)在數(shù)據(jù)庫(kù)ATable插入一條數(shù)據(jù),方法B執(zhí)行會(huì)在數(shù)據(jù)庫(kù)BTable插入一條數(shù)據(jù)

      事務(wù)傳播

      七種事務(wù)傳播行為詳解與示例

      在介紹七種事務(wù)傳播行為前,我們先設(shè)計(jì)一個(gè)場(chǎng)景,幫助大家理解,場(chǎng)景描述如下

      現(xiàn)有兩個(gè)方法A和B,方法A執(zhí)行會(huì)在數(shù)據(jù)庫(kù)ATable插入一條數(shù)據(jù),方法B執(zhí)行會(huì)在數(shù)據(jù)庫(kù)BTable插入一條數(shù)據(jù),偽代碼如下:

      //將傳入?yún)?shù)a存入ATablepubilc void A(a){    insertIntoATable(a);    }//將傳入?yún)?shù)b存入BTablepublic void B(b){    insertIntoBTable(b);}

      接下來(lái),我們看看在如下場(chǎng)景下,沒(méi)有事務(wù),情況會(huì)怎樣

      public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      在這里要做一個(gè)重要提示:Spring中事務(wù)的默認(rèn)實(shí)現(xiàn)使用的是AOP,也就是代理的方式,如果大家在使用代碼測(cè)試時(shí),同一個(gè)Service類中的方法相互調(diào)用需要使用注入的對(duì)象來(lái)調(diào)用,不要直接使用this.方法名來(lái)調(diào)用,this.方法名調(diào)用是對(duì)象內(nèi)部方法調(diào)用,不會(huì)通過(guò)Spring代理,也就是事務(wù)不會(huì)起作用

      以上偽代碼描述的一個(gè)場(chǎng)景,方法testMain和testB都沒(méi)有事務(wù),執(zhí)行testMain方法,那么結(jié)果會(huì)怎么樣呢?

      相信大家都知道了,就是a1數(shù)據(jù)成功存入ATable表,b1數(shù)據(jù)成功存入BTable表,而在拋出異常后b2數(shù)據(jù)存儲(chǔ)就不會(huì)執(zhí)行,也就是b2數(shù)據(jù)不會(huì)存入數(shù)據(jù)庫(kù),這就是沒(méi)有事務(wù)的場(chǎng)景。

      接下我們就開(kāi)始理解七種不同事務(wù)傳播類型的含義

      REQUIRED(Spring默認(rèn)的事務(wù)傳播類型)

      如果當(dāng)前沒(méi)有事務(wù),則自己新建一個(gè)事務(wù),如果當(dāng)前存在事務(wù),則加入這個(gè)事務(wù)

      源碼說(shuō)明如下:

          REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

      (示例1)根據(jù)場(chǎng)景舉栗子,我們?cè)趖estMain和testB上聲明事務(wù),設(shè)置傳播行為REQUIRED,偽代碼如下:

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.REQUIRED)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      該場(chǎng)景下執(zhí)行testMain方法結(jié)果如何呢?

      數(shù)據(jù)庫(kù)沒(méi)有插入新的數(shù)據(jù),數(shù)據(jù)庫(kù)還是保持著執(zhí)行testMain方法之前的狀態(tài),沒(méi)有發(fā)生改變。testMain上聲明了事務(wù),在執(zhí)行testB方法時(shí)就加入了testMain的事務(wù)(當(dāng)前存在事務(wù),則加入這個(gè)事務(wù)),在執(zhí)行testB方法拋出異常后事務(wù)會(huì)發(fā)生回滾,又testMain和testB使用的同一個(gè)事務(wù),所以事務(wù)回滾后testMain和testB中的操作都會(huì)回滾,也就使得數(shù)據(jù)庫(kù)仍然保持初始狀態(tài)

      (示例2)根據(jù)場(chǎng)景再舉一個(gè)栗子,我們只在testB上聲明事務(wù),設(shè)置傳播行為REQUIRED,偽代碼如下:

      public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.REQUIRED)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      這時(shí)的執(zhí)行結(jié)果又如何呢?

      數(shù)據(jù)a1存儲(chǔ)成功,數(shù)據(jù)b1和b2沒(méi)有存儲(chǔ)。由于testMain沒(méi)有聲明事務(wù),testB有聲明事務(wù)且傳播行為是REQUIRED,所以在執(zhí)行testB時(shí)會(huì)自己新建一個(gè)事務(wù)(如果當(dāng)前沒(méi)有事務(wù),則自己新建一個(gè)事務(wù)),testB拋出異常則只有testB中的操作發(fā)生了回滾,也就是b1的存儲(chǔ)會(huì)發(fā)生回滾,但a1數(shù)據(jù)不會(huì)回滾,所以最終a1數(shù)據(jù)存儲(chǔ)成功,b1和b2數(shù)據(jù)沒(méi)有存儲(chǔ)

      SUPPORTS

      當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方法執(zhí)行

      源碼注釋如下(太長(zhǎng)省略了一部分),其中里面有一個(gè)提醒翻譯一下就是:“對(duì)于具有事務(wù)同步的事務(wù)管理器,SUPPORTS與完全沒(méi)有事務(wù)稍有不同,因?yàn)樗x了可能應(yīng)用同步的事務(wù)范圍”。這個(gè)是與事務(wù)同步管理器相關(guān)的一個(gè)注意項(xiàng),這里不過(guò)多討論。

          SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

      (示例3)根據(jù)場(chǎng)景舉栗子,我們只在testB上聲明事務(wù),設(shè)置傳播行為SUPPORTS,偽代碼如下:

      public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.SUPPORTS)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      這種情況下,執(zhí)行testMain的最終結(jié)果就是,a1,b1存入數(shù)據(jù)庫(kù),b2沒(méi)有存入數(shù)據(jù)庫(kù)。由于testMain沒(méi)有聲明事務(wù),且testB的事務(wù)傳播行為是SUPPORTS,所以執(zhí)行testB時(shí)就是沒(méi)有事務(wù)的(如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方法執(zhí)行),則在testB拋出異常時(shí)也不會(huì)發(fā)生回滾,所以最終結(jié)果就是a1和b1存儲(chǔ)成功,b2沒(méi)有存儲(chǔ)。

      那么當(dāng)我們?cè)趖estMain上聲明事務(wù)且使用REQUIRED傳播方式的時(shí)候,這個(gè)時(shí)候執(zhí)行testB就滿足當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù),在testB拋出異常時(shí)事務(wù)就會(huì)回滾,最終結(jié)果就是a1,b1和b2都不會(huì)存儲(chǔ)到數(shù)據(jù)庫(kù)

      MANDATORY

      當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù),如果當(dāng)前事務(wù)不存在,則拋出異常。

      源碼注釋如下:

          MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

      (示例4)場(chǎng)景舉栗子,我們只在testB上聲明事務(wù),設(shè)置傳播行為MANDATORY,偽代碼如下:

      public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.MANDATORY)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      這種情形的執(zhí)行結(jié)果就是a1存儲(chǔ)成功,而b1和b2沒(méi)有存儲(chǔ)。b1和b2沒(méi)有存儲(chǔ),并不是事務(wù)回滾的原因,而是因?yàn)閠estMain方法沒(méi)有聲明事務(wù),在去執(zhí)行testB方法時(shí)就直接拋出事務(wù)要求的異常(如果當(dāng)前事務(wù)不存在,則拋出異常),所以testB方法里的內(nèi)容就沒(méi)有執(zhí)行。

      那么如果在testMain方法進(jìn)行事務(wù)聲明,并且設(shè)置為REQUIRED,則執(zhí)行testB時(shí)就會(huì)使用testMain已經(jīng)開(kāi)啟的事務(wù),遇到異常就正常的回滾了。

      REQUIRES_NEW

      創(chuàng)建一個(gè)新事務(wù),如果存在當(dāng)前事務(wù),則掛起該事務(wù)。

      可以理解為設(shè)置事務(wù)傳播類型為REQUIRES_NEW的方法,在執(zhí)行時(shí),不論當(dāng)前是否存在事務(wù),總是會(huì)新建一個(gè)事務(wù)。

      源碼注釋如下

          REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

      (示例5)場(chǎng)景舉栗子,為了說(shuō)明設(shè)置REQUIRES_NEW的方法會(huì)開(kāi)啟新事務(wù),我們把異常發(fā)生的位置換到了testMain,然后給testMain聲明事務(wù),傳播類型設(shè)置為REQUIRED,testB也聲明事務(wù),設(shè)置傳播類型為REQUIRES_NEW,偽代碼如下

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB    throw Exception;     //發(fā)生異常拋出}@Transactional(propagation = Propagation.REQUIRES_NEW)public void testB(){    B(b1);  //調(diào)用B入?yún)1    B(b2);  //調(diào)用B入?yún)2}

      這種情形的執(zhí)行結(jié)果就是a1沒(méi)有存儲(chǔ),而b1和b2存儲(chǔ)成功,因?yàn)閠estB的事務(wù)傳播設(shè)置為REQUIRES_NEW,所以在執(zhí)行testB時(shí)會(huì)開(kāi)啟一個(gè)新的事務(wù),testMain中發(fā)生的異常時(shí)在testMain所開(kāi)啟的事務(wù)中,所以這個(gè)異常不會(huì)影響testB的事務(wù)提交,testMain中的事務(wù)會(huì)發(fā)生回滾,所以最終a1就沒(méi)有存儲(chǔ),而b1和b2就存儲(chǔ)成功了。

      與這個(gè)場(chǎng)景對(duì)比的一個(gè)場(chǎng)景就是testMain和testB都設(shè)置為REQUIRED,那么上面的代碼執(zhí)行結(jié)果就是所有數(shù)據(jù)都不會(huì)存儲(chǔ),因?yàn)閠estMain和testMain是在同一個(gè)事務(wù)下的,所以事務(wù)發(fā)生回滾時(shí),所有的數(shù)據(jù)都會(huì)回滾

      NOT_SUPPORTED

      始終以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則掛起當(dāng)前事務(wù)

      可以理解為設(shè)置事務(wù)傳播類型為NOT_SUPPORTED的方法,在執(zhí)行時(shí),不論當(dāng)前是否存在事務(wù),都會(huì)以非事務(wù)的方式運(yùn)行。

      源碼說(shuō)明如下

          NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

      (示例6)場(chǎng)景舉栗子,testMain傳播類型設(shè)置為REQUIRED,testB傳播類型設(shè)置為NOT_SUPPORTED,且異常拋出位置在testB中,偽代碼如下

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.NOT_SUPPORTED)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      該場(chǎng)景的執(zhí)行結(jié)果就是a1和b2沒(méi)有存儲(chǔ),而b1存儲(chǔ)成功。testMain有事務(wù),而testB不使用事務(wù),所以執(zhí)行中testB的存儲(chǔ)b1成功,然后拋出異常,此時(shí)testMain檢測(cè)到異常事務(wù)發(fā)生回滾,但是由于testB不在事務(wù)中,所以只有testMain的存儲(chǔ)a1發(fā)生了回滾,最終只有b1存儲(chǔ)成功,而a1和b1都沒(méi)有存儲(chǔ)

      NEVER

      不使用事務(wù),如果當(dāng)前事務(wù)存在,則拋出異常

      很容易理解,就是我這個(gè)方法不使用事務(wù),并且調(diào)用我的方法也不允許有事務(wù),如果調(diào)用我的方法有事務(wù)則我直接拋出異常。

      源碼注釋如下:

          NEVER(TransactionDefinition.PROPAGATION_NEVER),

      (示例7)場(chǎng)景舉栗子,testMain設(shè)置傳播類型為REQUIRED,testB傳播類型設(shè)置為NEVER,并且把testB中的拋出異常代碼去掉,則偽代碼如下

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB}@Transactional(propagation = Propagation.NEVER)public void testB(){    B(b1);  //調(diào)用B入?yún)1    B(b2);  //調(diào)用B入?yún)2}

      該場(chǎng)景執(zhí)行,直接拋出事務(wù)異常,且不會(huì)有數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)。由于testMain事務(wù)傳播類型為REQUIRED,所以testMain是運(yùn)行在事務(wù)中,而testB事務(wù)傳播類型為NEVER,所以testB不會(huì)執(zhí)行而是直接拋出事務(wù)異常,此時(shí)testMain檢測(cè)到異常就發(fā)生了回滾,所以最終數(shù)據(jù)庫(kù)不會(huì)有數(shù)據(jù)存入。

      NESTED

      如果當(dāng)前事務(wù)存在,則在嵌套事務(wù)中執(zhí)行,否則REQUIRED的操作一樣(開(kāi)啟一個(gè)事務(wù))

      這里需要注意兩點(diǎn):

    • 和REQUIRES_NEW的區(qū)別

      REQUIRES_NEW是新建一個(gè)事務(wù)并且新開(kāi)啟的這個(gè)事務(wù)與原有事務(wù)無(wú)關(guān),而NESTED則是當(dāng)前存在事務(wù)時(shí)(我們把當(dāng)前事務(wù)稱之為父事務(wù))會(huì)開(kāi)啟一個(gè)嵌套事務(wù)(稱之為一個(gè)子事務(wù))。
      在NESTED情況下父事務(wù)回滾時(shí),子事務(wù)也會(huì)回滾,而在REQUIRES_NEW情況下,原有事務(wù)回滾,不會(huì)影響新開(kāi)啟的事務(wù)。

    • 和REQUIRED的區(qū)別

      REQUIRED情況下,調(diào)用方存在事務(wù)時(shí),則被調(diào)用方和調(diào)用方使用同一事務(wù),那么被調(diào)用方出現(xiàn)異常時(shí),由于共用一個(gè)事務(wù),所以無(wú)論調(diào)用方是否catch其異常,事務(wù)都會(huì)回滾
      而在NESTED情況下,被調(diào)用方發(fā)生異常時(shí),調(diào)用方可以catch其異常,這樣只有子事務(wù)回滾,父事務(wù)不受影響

      (示例8)場(chǎng)景舉栗子,testMain設(shè)置為REQUIRED,testB設(shè)置為NESTED,且異常發(fā)生在testMain中,偽代碼如下

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    testB();    //調(diào)用testB    throw Exception;     //發(fā)生異常拋出}@Transactional(propagation = Propagation.NESTED)public void testB(){    B(b1);  //調(diào)用B入?yún)1    B(b2);  //調(diào)用B入?yún)2}

      該場(chǎng)景下,所有數(shù)據(jù)都不會(huì)存入數(shù)據(jù)庫(kù),因?yàn)樵趖estMain發(fā)生異常時(shí),父事務(wù)回滾則子事務(wù)也跟著回滾了,可以與(示例5)比較看一下,就找出了與REQUIRES_NEW的不同

      (示例9)場(chǎng)景舉栗子,testMain設(shè)置為REQUIRED,testB設(shè)置為NESTED,且異常發(fā)生在testB中,偽代碼如下

      @Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //調(diào)用A入?yún)1    try{        testB();    //調(diào)用testB    }catch(Exception e){    }    A(a2);}@Transactional(propagation = Propagation.NESTED)public void testB(){    B(b1);  //調(diào)用B入?yún)1    throw Exception;     //發(fā)生異常拋出    B(b2);  //調(diào)用B入?yún)2}

      這種場(chǎng)景下,結(jié)果是a1,a2存儲(chǔ)成功,b1和b2存儲(chǔ)失敗,因?yàn)檎{(diào)用方catch了被調(diào)方的異常,所以只有子事務(wù)回滾了。

      同樣的代碼,如果我們把testB的傳播類型改為REQUIRED,結(jié)果也就變成了:沒(méi)有數(shù)據(jù)存儲(chǔ)成功。就算在調(diào)用方catch了異常,整個(gè)事務(wù)還是會(huì)回滾,因?yàn)椋{(diào)用方和被調(diào)方共用的同一個(gè)事務(wù)

      轉(zhuǎn)自于:https://zhuanlan.zhihu.com/p/148504094

    •  
      (文/史舒文)
      免責(zé)聲明
      本文僅代表作發(fā)布者:史舒文個(gè)人觀點(diǎn),本站未對(duì)其內(nèi)容進(jìn)行核實(shí),請(qǐng)讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,需自行承擔(dān)相應(yīng)責(zé)任。涉及到版權(quán)或其他問(wèn)題,請(qǐng)及時(shí)聯(lián)系我們刪除處理郵件:weilaitui@qq.com。
       

      Copyright ? 2016 - 2025 - 企資網(wǎng) 48903.COM All Rights Reserved 粵公網(wǎng)安備 44030702000589號(hào)

      粵ICP備16078936號(hào)

      微信

      關(guān)注
      微信

      微信二維碼

      WAP二維碼

      客服

      聯(lián)系
      客服

      聯(lián)系客服:

      在線QQ: 303377504

      客服電話: 020-82301567

      E_mail郵箱: weilaitui@qq.com

      微信公眾號(hào): weishitui

      客服001 客服002 客服003

      工作時(shí)間:

      周一至周五: 09:00 - 18:00

      反饋

      用戶
      反饋

      午夜久久久久久网站,99久久www免费,欧美日本日韩aⅴ在线视频,东京干手机福利视频
        <strike id="ca4is"><em id="ca4is"></em></strike>
      • <sup id="ca4is"></sup>
        • <s id="ca4is"><em id="ca4is"></em></s>
          <option id="ca4is"><cite id="ca4is"></cite></option>
        • 主站蜘蛛池模板: 久久久久久亚洲精品| 国产精品国产自线拍免费软件| 国产真实乱freesex| 十分钟免费视频高清完整版www| 亚洲人成77777在线播放网站| 一本一道波多野结衣一区| 美女被免费喷白浆视频| 扒开美妇白臀扒挺进在线视频| 国产亚洲综合精品一区二区三区| 亚洲入口无毒网址你懂的 | 最新亚洲精品国自产在线观看| 天美传媒一区二区三区| 免费精品久久天干天干| 久久久国产精品亚洲一区| 久碰人澡人澡人澡人澡人视频| 狠狠入ady亚洲精品| 成人免费视频网| 午夜视频在线观看国产| 一区二区三区四区欧美 | 国产精品久久久久久久久久久不卡| 免费又黄又爽1000禁片| h在线观看网站| 精品无码一区二区三区亚洲桃色| 最新国产三级久久| 国产精品林美惠子在线播放| 亚洲视频手机在线| xxxxx国产| 精品不卡一区中文字幕| 天堂网在线资源www最新版| 亚洲熟妇色自偷自拍另类| hd日本扒衣党视频播放| 欧美香蕉爽爽人人爽| 在线看欧美日韩中文字幕| 亚洲欧美综合区自拍另类| 亚洲色图第一页| 欧美人善交videosg| 国产高清小视频| 亚洲狠狠色丁香婷婷综合| a拍拍男女免费看全片| 橘梨纱视频一区二区在线观看| 国产精品无码MV在线观看|