1. 程式人生 > >阿里大牛帶你深入分析spring事務傳播行為

阿里大牛帶你深入分析spring事務傳播行為

開發十年,就只剩下這套架構體系了! >>>   

spring框架封裝了很多有用的功能和元件,便於在專案開發中快速高效的呼叫,其中spring的事務使用非常簡單,只需要在用到事務的地方加一行註解即可:

1@Transactional

但越是看起來簡單的東西,就越多坑,為何如此?

不是因為別人造的輪子有問題,而是我們在用輪子的時候,只會用,不知其原理,因而不能在實際使用場景中很好的把握它。

spring的事務傳播行為在實戰中是非常重要的,但90%的人只會@Transactional,在此很有必要給大家分享一下。

在事務註解的引數中,我們可以看到有這樣的一個引數:

 

 

這個引數就是用來控制事務傳播行為的,下面對這個引數進行詳細的解答每一個引數代表的傳播行為以及在講解在實際場景中應該選擇引數值。

文章提綱:

Spring事務傳播行為

事務傳播行為剖析(例項)

引數行為場景應用(例項)

1.Spring事務傳播行為:

spring支援7種事務傳播行為,確定客戶端和被呼叫端的事務邊界(說得通俗一點就是多個具有事務控制的service的相互呼叫時所形成的複雜的事務邊界控制)下圖所示為7鍾事務傳播機制:

傳播行為(XML)含義

REQUIRED:表示當前方法必須在一個具有事務的上下文中執行,如有客戶端有事務在進行,那麼被呼叫端將在該事務中執行,否則的話重新開啟一個事務(如果被呼叫端發生異常,那麼呼叫端和被呼叫端事務都將回滾)。

SUPPORTS:表示當前方法不必需要具有一個事務上下文,但是如果有一個事務的話,它也可以在這個事務中執行。

MANDATORY:表示當前方法必須在一個事務中執行,如果沒有事務,將丟擲異常

NESTED:表示如果當前方法正有一個事務在執行中,則該方法應該執行在一個巢狀事務中,被巢狀的事務可以獨立於被封裝的事務中進行提交或者回滾。如果封裝事務存在,並且外層事務丟擲異常回滾,那麼內層事務必須回滾,反之,內層事務並不影響外層事務。如果封裝事務不存在,則同REQUIRED的一樣。

NEVER:表示當方法務不應該在一個事務中執行,如果存在一個事務,則丟擲異常。

REQUIRES_NEW:表示當前方法必須執行在它自己的事務中。一個新的事務將啟動,而且如果有一個現有的事務在執行的話,則這個方法將在執行期被掛起,直到新的事務提交或者回滾才恢復執行。

NOT_SUPPORTED:表示該方法不應該在一個事務中執行。如果有一個事務正在執行,他將在執行期被掛起,直到這個事務提交或者回滾才恢復執行。

2.事務傳播行為剖析(例項)

假設有類A的方法methodB(),有類B的方法methodB().

REQUIRED

如果B的方法methodB()的事務傳播特性是required,那麼如下圖

 

 

A.methodA()呼叫B的methodB()方法,那麼如果A的方法包含事務,則B的方法則不從新開啟事務,

1、 如果B的methodB()丟擲異常,A的methodB()沒有捕獲,則A和B的事務都會回滾;

2、 如果B的methodB()執行期間異常會導致B的methodB()的回滾,A如果捕獲了異常,並正常提交事務,則會發生Transaction rolled back because it has been marked as rollback-only的異常。

3、 如果A的methodA()執行期間異常,則A和B的Method的事務都會被回滾

SUPPORTS

如果B的方法methodB()的事務傳播特性是supports,麼如下圖

 

 

歡迎工作一到五年的Java工程師朋友們加入Java高階架構:790147974

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,

MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)

合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

 

A.methodA()呼叫B的methodB()方法,那麼如果A的方法包含事務,則B執行在此事務環境中,如果A的方法不包含事務,則B執行在非事務環境;

1、如果A沒有事務,則A和B的執行出現異常都不會回滾。

2、如果A有事務,A的method方法執行丟擲異常,B.methodB和A.methodA都會回滾。

3、如果A有事務,B.method丟擲異常,B.methodB和A.methodA都會回滾,如果A捕獲了B.method丟擲的異常,則會出現異常Transactionrolled back because it has been marked as rollback-only。

MANDATORY

表示當前方法必須在一個事務中執行,如果沒有事務,將丟擲異常,如下圖呼叫關係:

 

 

B.methodB()事務傳播特性定義為:MANDATORY

1、如果A的methoda()方法沒有事務執行環境,則B的methodB()執行的時候會報如下異常:No existingtransaction found for transaction marked with propagation 'mandatory'

2、如果A的Methoda()方法有事務並且執行過程中丟擲異常,則A.methoda()和B.methodb()執行的操作被回滾;

3、如果A的methoda()方法有事務,則B.methodB()丟擲異常時,A的methoda()和B.methodB()都會被回滾;如果A捕獲了B.method丟擲的異常,則會出現異常Transaction rolled back because ithas been marked as rollback-only

NESTED

如有一下方法呼叫關係,如圖:

 

 

B的methodB()定義的事務為NESTED;

1、如果A的MethodA()不存在事務,則B的methodB()執行在一個新的事務中,B.method()丟擲的異常,B.methodB()回滾,但A.methodA()不回滾;如果A.methoda()丟擲異常,則A.methodA()和B.methodB()操作不回。

2、 如果A的methodA()存在事務,則A的methoda()丟擲異常,則A的methoda()和B的Methodb()都會被回滾;

3、 如果A的MethodA()存在事務,則B的methodB()丟擲異常,B.methodB()回滾,如果A不捕獲異常,則A.methodA()和B.methodB()都會回滾,如果A捕獲異常,則B.methodB()回滾,A不回滾;

NEVER

表示事務傳播特性定義為NEVER的方法不應該執行在一個事務環境中

有如下呼叫關係:

 

 

如果B.methodB()的事務傳播特性被定義為NEVER,則如果A.methodA()方法存在事務,則會出現異常Existingtransaction found for transaction marked with propagation 'never'。

REQUIRES_NEW

表示事務傳播特性定義為REQUIRES_NEW的方法需要執行在一個新的事務中。

如有一下呼叫關係:B.methodB()事務傳播特性為REQUIRES_NEW.

 

 

1、 如果A存在事務,A.methodA()丟擲異常,A.methodA()的事務被回滾,但B.methodB()事務不受影響;如果B.methodB()丟擲異常,A不捕獲的話,A.methodA()和B.methodB()的事務都會被回滾。如果A捕獲的話,A.methodA()的事務不受影響但B.methodB()的事務回滾。

NOT_SUPPORTED

表示該方法不應該在一個事務中執行。如果有一個事務正在執行,他將在執行期被掛起,直到這個事務提交或者回滾才恢復執行。

如有一下呼叫關係圖:

 

 

如果B.methodB()方法傳播特性被定義為:NOT_SUPPORTED。

1、 如果A.methodA()存在事務,如果B.methodB()丟擲異常,A.methodA()不捕獲的話,A.methodA()的事務被回滾,而B.methodB()出現異常前資料庫操作不受影響。如果A.methodA()捕獲的話,則A.methodA()的事務不受影響,B.methodB()異常丟擲前的資料操作不受影響。

3. 引數行為場景應用(例項)

1、 在一個話費充值業務處理邏輯中,有如下圖所示操作:

 

 

業務需要扣款操作和建立訂單操作同成功或者失敗,因此,charger()和order()的事務不能相互獨立,需要包含在chargeHandle()的事務中;

通過以上需求,可以給charge()和order()的事務傳播行為定義成:MANDATORY

只要charge()或者order()丟擲異常整個chargeHandle()都一起回滾,即使chargeHandle()捕獲異常也沒用,不允許提交事務。

2、 如果業務需求沒接受到一次請求到要記錄日誌到資料庫,如下圖:

 

 

因為log()的操作不管扣款和建立訂單成功與否都要生成日誌,並且日誌的操作成功與否不影響充值處理,所以log()方法的事務傳播行為可以定義為:REQUIRES_NEW.

在訂單的售後處理中,更新完訂單金額後,需要自動統計銷售報表,如下圖所示:

 

 

根據業務可知,售後是已經處理完訂單的充值請求後的功能,是對訂單的後續管理,統計報表report()方法耗時較長,因此,我們需要設定report()的事務傳播行為為:NEVER,表示不適合在有事務的操作中呼叫,因為report()太耗時。

在銀行新增銀行卡業務中,需要執行兩個操作,一個是儲存銀行卡資訊,一個是登記新建立的銀行卡資訊,其中登記銀行卡資訊成功與否不影響銀行卡的建立。

 

由以上需求,我們可知對於regster()方法的事務傳播行為,可以設定為NESTED,action()事務的回滾,regster()儲存的資訊就沒意義,也就需要跟著回滾,而regster()的回滾不影響action()事務;insert()的事務傳播行為可以設定為REQUIRED, MANDATORY,即insert()回滾事務,action()的事務必須跟著回滾。

歡迎工作一到五年的Java工程師朋友們加入Java高階架構:705127209 

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,

MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)

合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一