亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于Spring?@Transactional事務(wù)傳播機制詳解

 更新時間:2023年08月04日 11:40:09   作者:Endwas  
我們?nèi)粘9ぷ髦袠O少使用事務(wù)傳播級別,單純只是使用事務(wù)和rollbackfor拋出異常來解決事務(wù)問題,但其實我們很多時候使用的是不正確的,或者說會造成事務(wù)粒度過大,本文詳解一下事務(wù)傳播級別,也讓自己更好地處理事務(wù)問題,需要的朋友可以參考下

Spring事務(wù)傳播機制

1.什么是事務(wù)傳播機制?

舉個栗子,方法A是一個事務(wù)的方法,方法A執(zhí)行過程中調(diào)用了方法B,那么方法B有無事務(wù)以及方法B對事務(wù)的要求不同都會對方法A的事務(wù)具體執(zhí)行造成影響,同時方法A的事務(wù)對方法B的事務(wù)執(zhí)行也有影響,這種影響具體是什么就由兩個方法所定義的事務(wù)傳播類型所決定。

簡單說就是,我們方法調(diào)用通常是,一個方法調(diào)用另外一個,而不同方法可以有不同的事務(wù),所以傳播機制就是指在多個方法,事務(wù)要如何傳播。

2.Spring事務(wù)傳播類型Propagation介紹

一共有七種傳播類型

  • Propagation.REQUIRED
  • Propagation.SUPPORTS
  • Propagation.MANDATORY
  • Propagation.REQUIRED_NEW
  • Propagation.NOT_SUPPORTED
  • Propagation.NESTED
  • Propagation.NEVER

本文從案例結(jié)合解釋一下不同傳播類型下多個@Transactional方法會發(fā)生什么?在遇到異常情況下,不同傳播機制會產(chǎn)生什么影響。

1. Propagation.REQUIRED

這是默認(rèn)的傳播機制,我們最常用的一種,也是@Transactional默認(rèn)的一種

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

// 示例1:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.REQUIRED)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

簡單來說就是,開啟一個事務(wù),上面的案例就是當(dāng)main方法如果沒開啟事務(wù),那么sub方法就會開啟,如果main方法已經(jīng)@Transactional開啟了事務(wù),sub方法就會加入外層方法的事務(wù),所以上面方法執(zhí)行在遇到異常時候會全部回滾

結(jié)果:

A、B、C全部無法插入。

// 示例2:
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.REQUIRED)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

結(jié)果:

A插入成功,BC開啟新的事務(wù),遇到異?;貪L,B、C無法插入

2. Propagation.SUPPORTS

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

// 示例3:
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.SUPPORTS)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

這個和REQUIRED很像,但是里層的sub方法事務(wù)取決于main方法,如果main方法有開啟那么里面的就和外層事務(wù)一起,如果發(fā)生異常全部回滾。

結(jié)果:

A、B插入成功,C無法插入因為發(fā)生異常

3. Propagation.MANDATORY

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

// 示例4:
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.MANDATORY)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

這種情形的執(zhí)行結(jié)果就是insertA存儲成功,而insertB和insertC沒有存儲。b和c沒有存儲,并不是事務(wù)回滾的原因,而是因為main方法沒有聲明事務(wù),在去執(zhí)行sub方法時就直接拋出事務(wù)要求的異常(如果當(dāng)前事務(wù)不存在,則拋出異常),所以sub方法里的內(nèi)容就完全沒有執(zhí)行。

結(jié)果:

A插入成功,B、C無法插入,方法拋出異常

那么當(dāng)main方法有事務(wù)的情況下

// 示例5:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.MANDATORY)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

結(jié)果:

A、B、C全部無法插入,A、B回滾

4. Propagation.REQUIRED_NEW

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

// 示例5:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
    throw RuntimeException;     //發(fā)生異常拋出
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sub(){
    insertB();  //插入B
    insertC();  //調(diào)用C

因為sub方法會開啟一個新的事務(wù),所以main方法拋出的異常并不會影響sub方法的提交

結(jié)果:

A插入失敗,B、C能插入成功

5. Propagation.NOT_SUPPORTED

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

// 示例6:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

示例6因為當(dāng)main方法有事務(wù)的時候,就會掛起當(dāng)前事務(wù)即main以事務(wù)運行,sub不以事務(wù)運行

所以最終結(jié)果:

A因為sub拋出異常事務(wù)回滾,插入失敗,B因為不以事務(wù)運行插入成功,C因為遇到異常,后續(xù)不會執(zhí)行,所以插入失敗。

// 示例7:
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

示例7這種情況就是所有方法都不會以事務(wù)運行,A、B均能插入成功,C無法插入

6. Propagation.NEVER

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

// 示例7:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.NEVER)
public void sub(){
    insertB();  //插入B
    insertC();  //調(diào)用C

sub因為是Never所以是不會執(zhí)行直接拋出錯誤,所以main的事務(wù)遇到異常直接回滾,所以A回滾無法插入,B、C不會插入。

7. Propagation.NESTED

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

// 示例7:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    service.sub();   // 調(diào)用其他方法
    throw RuntimeException;     //發(fā)生異常拋出
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.NESTED)
public void sub(){
    insertB();  //插入B
    insertC();  //調(diào)用C

這個是最需要理解的一種傳播機制,要理清楚嵌套(父子)事務(wù),main的是父事務(wù),sub是子事務(wù),main發(fā)生異常全部都會回滾。

結(jié)果:

A、B、C全部回滾

// 示例8:
@Transactional(propagation = Propagation.REQUIRED)
public void main(){
    insertA();  // 插入A 
    try {
   		 service.sub();   // 調(diào)用其他方法
	} catch (Exception e) {
	}
	insertD();
}
// 兩個Service中調(diào)用,如果同一個要注意不能用this調(diào)用,事務(wù)不會起作用
@Transactional(propagation = Propagation.NESTED)
public void sub(){
    insertB();  //插入B
    throw RuntimeException;     //發(fā)生異常拋出
    insertC();  //調(diào)用C

示例8,子事務(wù)發(fā)生異常拋出,但父事務(wù)catch掉了,那么這個時候main方法就相當(dāng)于正常執(zhí)行沒有發(fā)生異常,那么就只有子事務(wù)回滾。

結(jié)果:

A、D插入成功,B、C插入失敗

  • REQUIRED
    • 內(nèi)外同一個事務(wù),任何一個地方拋出異常全部一起回滾。
  • REQUIRED_NEW
    • 內(nèi)部開啟一個新的事務(wù),外部事務(wù)回滾并不會影響內(nèi)部的事務(wù),而如果內(nèi)部事務(wù)拋出被catch也不會影響外部事務(wù)。

怎么樣快速記憶,七個分四組,221這樣記,兩個一對互相類似

傳播類型含義
group1Propagation.REQUIRED如果當(dāng)前已有事務(wù)則加入當(dāng)前事務(wù),否則開啟新的事務(wù)
group1Propagation.REQUIRED_NEW無論當(dāng)前是否有事務(wù)都開啟新的事務(wù)
group2Propagation.SUPPORTED如果當(dāng)前事務(wù)存在就加入事務(wù),否則以非事務(wù)運行
group2Propagation.NOT_SUPPORTED始終以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則掛起當(dāng)前事務(wù)
group3Propagation.NEVER不使用事務(wù),如果當(dāng)前事務(wù)存在,則拋出異常
group3Propagation.MANDATORY當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù),如果當(dāng)前事務(wù)不存在,則拋出異常。
group4Propagation.NESTED父子(嵌套)事務(wù),父回滾全回滾,子回滾不影響父事務(wù)

3.具體案例

單純講案例比較枯燥,會覺得工作中什么情況會使用到呢,這邊就舉一個例子來講解一下。

在下單時候,我們最主要是寫入訂單、然后添加積分,最后記錄日志

 @Service
   public class OrderServiceImpl implements OrderService{
        @Transactional
        public void placeOrder(OrderDTO orderDTO){
            try {
                pointService.addPoint(Point point);
            } catch (Exception e) {
               // 記錄錯誤信息
            }
            //省略...
        }
        //省略...
   }
   @Service
   public class PointServiceImpl implements PointService{
        @Transactional(propagation = Propagation.NESTED)
        public void addPoint(Point point){
            try {
                recordService.addRecord(Record record);
            } catch (Exception e) {
               //省略...
            }
            //省略...
        }
        //省略...
   }
   @Service
   public class RecordServiceImpl implements RecordService{
        @Transactional(propagation = Propagation.NOT_SUPPORTED)
        public void addRecord(Record record){
            //省略...
        }
        //省略...
   }

下單的操作不會影響添加積分的操作,所以我們使用NESTED,下單只要成功,添加積分可以成功或失敗,失敗的話就錯誤信息后續(xù)補償。而記錄日志我們可以有也可以沒有,就可以設(shè)置為NOT_SUPPORTED不開啟事務(wù),使得事務(wù)的方法能盡可能的精簡,避免一個很大的事務(wù)方法。

總結(jié)

本文講解了Spring事務(wù)的七種傳播機制,我們可以根據(jù)具體的類型,具體設(shè)置,避免事務(wù)的方法過于長,一個事務(wù)里面調(diào)用的庫表越多,就越有可能造成死鎖,所以我們要根據(jù)具體的需要拆分使用。

以上就是關(guān)于Spring @Transactional事務(wù)傳播機制詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring @Transactional事務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論