天天看點

spring 事務傳播行為執行個體分析

Spring事務傳播行為:

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

o   

傳播行為

含義

PROPAGATION_REQUIRED(XML檔案中為REQUIRED)

表示目前方法必須在一個具有事務的上下文中運作,如有用戶端有事務在進行,那麼被調用端将在該事務中運作,否則的話重新開啟一個事務。(如果被調用端發生異常,那麼調用端和被調用端事務都将復原)

PROPAGATION_SUPPORTS(XML檔案中為SUPPORTS)

表示目前方法不必需要具有一個事務上下文,但是如果有一個事務的話,它也可以在這個事務中運作

PROPAGATION_MANDATORY(XML檔案中為MANDATORY)

表示目前方法必須在一個事務中運作,如果沒有事務,将抛出異常

PROPAGATION_NESTED(XML檔案中為NESTED)

表示如果目前方法正有一個事務在運作中,則該方法應該運作在一個嵌套事務中,被嵌套的事務可以獨立于被封裝的事務中進行送出或者復原。如果封裝事務存在,并且外層事務抛出異常復原,那麼内層事務必須復原,反之,内層事務并不影響外層事務。如果封裝事務不存在,則同PROPAGATION_REQUIRED的一樣

PROPAGATION_NEVER(XML檔案中為NEVER)

表示當方法務不應該在一個事務中運作,如果存在一個事務,則抛出異常

PROPAGATION_REQUIRES_NEW(XML檔案中為REQUIRES_NEW)

表示目前方法必須運作在它自己的事務中。一個新的事務将啟動,而且如果有一個現有的事務在運作的話,則這個方法将在運作期被挂起,直到新的事務送出或者復原才恢複執行。

PROPAGATION_NOT_SUPPORTED(XML檔案中為NOT_SUPPORTED)

表示該方法不應該在一個事務中運作。如果有一個事務正在運作,他将在運作期被挂起,直到這個事務送出或者復原才恢複執行

例子講解以上七中事務傳播機制

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

1)     PROPAGATION_REQUIRED

如果B的方法methodB()的事務傳播特性是propagation_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的事務都會被復原

2)     PROPAGATION_SUPPORTS

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

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。

3)     PROPAGATION_MANDATORY

表示目前方法必須在一個事務中運作,如果沒有事務,将抛出異常,如下圖調用關系:

B.methodB()事務傳播特性定義為:PROPAGATION_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

4)     PROPAGATION_NESTED

如有一下方法調用關系,如圖:

B的methodB()定義的事務為PROPAGATION_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不復原;

5)PROPAGATION_NEVER

表示事務傳播特性定義為PROPAGATION_NEVER的方法不應該運作在一個事務環境中

有如下調用關系:

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

6)PROPAGATION_REQUIRES_NEW

      表示事務傳播特性定義為PROPAGATION_REQUIRES_NEW的方法需要運作在一個新的事務中。

如有一下調用關系:B.methodB()事務傳播特性為PROPAGATION_REQUIRES_NEW.

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

7) PROPAGATION_NOT_SUPPORTED

表示該方法不應該在一個事務中運作。如果有一個事務正在運作,他将在運作期被挂起,直到這個事務送出或者復原才恢複執行。

如有一下調用關系圖:

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

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

實際場景中的七大事務傳播行為的使用

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

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

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

隻要charge()或者order()抛出異常整個chargeHandle()都一起復原,即使chargeHandle()捕獲異常也沒用,不允許送出事務。

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

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

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

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

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

由以上需求,我們可知對于regster()方法的事務傳播行為,可以設定為PROPAGATION_NESTED,action()事務的復原,regster()儲存的資訊就沒意義,也就需要跟着復原,而regster()的復原不影響action()事務;insert()的事務傳播行為可以設定為PROPAGATION_REQUIRED, PROPAGATION_MANDATORY,即insert()復原事務,action()的事務必須跟着復原。