課程分組的時候分到了Spring傳播機制的內容,研究整理了一下。
一、事務傳播行為和事務傳播機制
事務傳播行為:一般發生在事務嵌套的場景中,比如一個有事務的方法里面調用了另外一個有事務的方法
這個時候就會產生事務邊界控制的問題,即兩個方法是各自作為獨立的事務提交還是內層的事務合並到外層的事務一起提交
Spring規定了七大傳播機制來解決邊界控制的問題。
二、七大傳播機制
| 傳播機制 | 說明 |
|---|---|
| PROPAGATION_REQUIRED | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。 |
| PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
| PROPAGATION_MANDATORY | 使用當前的事務,如果當前沒有事務,就拋出異常。 |
| PROPAGATION_REQUIRES_NEW | 新建事務,如果當前存在事務,把當前事務掛起。 |
| PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
| PROPAGATION_NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常。 |
| PROPAGATION_NESTED | 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
三、對比理解及舉例
第一組
| 傳播機制 | 通俗解釋 |
|---|---|
| PROPAGATION_NEVER | 強制以非事務的方式運行,外層有事務,將會產生異常 |
| PROPAGATION_MANDATORY | 強制加入外層事務,外層沒有事務,則會產生異常 |

舉例:
在充值處理這個業務中,調用了扣款和訂單生成兩個方法,充值處理業務需要扣款操作和訂單生成操作同成功或者失敗,所以需要把這兩個方法放到同一個事務中運行;所以可以指定這兩個方法的傳播機制為MANDATORY,這樣它們就會都加入到外層事務,處於一個事務中,可以保證同成功或失敗。
第二組
| 傳播機制 | 通俗解釋 |
|---|---|
| PROPAGATION_REQUIRED(默認的機制) | 需要在事務中執行,外層有事務則加入,沒有則自己創建一個事務 |
| PROPAGATION_REQUIRES_NEW | 需要在一個新的事務中執行,這個新事務獨立於外層事務,互不影響 |

舉例:
在充值處理這個業務中,新增一個日志記錄的功能。日志記錄要求充值處理操作成功或者失敗都需要執行該方法,日志記錄的成功與否也不應該對充值處理的事務造成影響,所以可以將它的傳播機制設為REQUIRES_NEW,為其開啟一個新的事務,與外層的充值處理的事務獨立。
第三組
| 傳播機制 | 通俗解釋 |
|---|---|
| PROPAGATION_SUPPORTS | 支持外層,外層有事務就加入,沒有就以非事務方式運行 |
| PROPAGATION_NOT_SUPPORTED | 以非事務的方式運行,執行的時候先將外層事務掛起,允許外層有事務 |

舉例:
新增一個短信通知功能,短信通知不涉及數據庫的操作,所以不需要事務的支持,可以設置傳播機制為NOT_SUPPORTED
PROPAGATION_NESTED
嵌套事務:
- 它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint。
- 如果這個嵌套事務失敗, 將會回滾到此 savepoint。而不是整個事務的回滾。
區別:前面的3組傳播機制中,回滾的單位都是事務,而NESTED支持事務的分割,以savepoint為單位進行回滾。
四、總結
REQUIRES_NEW、NESTED、REQUIRED是最常用的三種傳播機制,詳細對比一下三者的區別。
方法A中調用方法B
| 狀態 | REQUIRES_NEW(兩個獨立事務) | NESTED(B的事務嵌套在A的事務中) | REQUIRED(同一個事務) |
|---|---|---|---|
| A異常B正常 | A回滾,B正常提交 | A與B一起回滾 | A與B一起回滾 |
| A正常B異常 | B先回滾,A再正常提交 | B先回滾,A再正常提交 | A與B一起回滾 |
| A正常B正常 | B先提交,A再提交 | A與B一起提交 | A與B一起提交 |
兩兩對比
-
NESTED和REQUIRED修飾的內部方法都屬於外圍方法事務,如果外圍方法拋出異常,這兩種方法的事務都會被回滾。但是REQUIRED是加入外圍方法事務,所以和外圍事務同屬於一個事務,一旦REQUIRED事務拋出異常被回滾,外圍方法事務也將被回滾。而NESTED是外圍方法的子事務,有單獨的保存點,所以NESTED方法拋出異常被回滾,不會影響到外圍方法的事務。
-
NESTED和REQUIRES_NEW都可以做到內部方法事務回滾而不影響外圍方法事務。但是因為NESTED是嵌套事務,所以外圍方法回滾之后,作為外圍方法事務的子事務也會被回滾。而REQUIRES_NEW是通過開啟新的事務實現的,內部事務和外圍事務是兩個事務,外圍事務回滾不會影響內部事務。
