Spring事務的傳播級別
一、簡單說明
傳播屬性 | 描述 |
---|---|
PROPAGATION_REQUIRED | 如果當前沒有事務,就創建一個事務,如果當前存在事務,就加入該事務。 |
PROPAGATION_REQUIRED_NEW | 當前的方法必須啟動新事務,並在它自己的事務內運行,不管是否存著事務,都開啟新事務。 |
PROPAGATION_SUPPORTS | 如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務的方式執行。 |
PROPAGATION_NOT_SUPPORTED | 當前的方法不應該運行在事務中,如果有運行的事務,將它掛起 |
PROPAGATION_MANDATORY | 如果當前存在事務,就加入當前事務,如果當前不存在事務,就拋出異常 |
PROPAGATION_NEVER | 當前的方法不應該運行在事務中,如果當前存在事務,就拋出異常 |
PROPAGATION_NESTED | 如果有事務在運行,當前的方法就應該在這個事務的嵌套事務內運行,否則,就啟動一個新的事務,並在它自己的事務內運行。 |
二、具體案例描述
1.PROPAGATION_REQUIRED
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodB(){
doSomething;
}
在兩個方法的事務傳播級別都是PROPAGATION_REQURIED的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B不會就不會再開啟一個新的事務,方法B會直接加入方法A的事務中執行,這樣如果在執行方法B的時候出了異常導致事務回滾,則B的方法和A的方法都會回滾。如果A的doPreSomething()和方法B都執行成功了,但是在執行doSufSomething()方法的時候拋出了異常導致事務回滾,則doSufSomething()、methodB()和doPreSomething()都會回滾。
如果不通過方法A而單獨調用方法B,則會開啟一個事務。
PROPAGATION_REQURIED所有方法公用一個事務,要麼一起成功提交,要麼一起失敗回滾。
如果嵌套執行的方法要求一起執行成功或者一起回滾,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
執行方法B
執行方法A的doSufSomething
提交或回滾事務
2.PROPAGATION_REQUIRED_NEW
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
dosufSomething;
}
@Transactional(propagation=PROPAGATION_REQUIRED_NEW)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_REQUIRED_NEW的時候。
如果調用方法A,會開啟一個事務,在方法內部調用方法B,方法B會自己再開啟一個事務,然後方法B在自己的事務內部執行,如果方法B執行失敗拋出異常,那麼事務B會進行回滾,事務A不會受到影響可以繼續執行,如果在方法B執行成功,方法B的事務會單獨進行提交;B提交事務之後接著執行A的doSufSomething()方法,如果執行成功提交A的事務,如果拋出異常,則只回滾A的事務,對B的事務不會進行影響,也就說B的事務不會進行回滾。
如果不通過方法A而單獨調用方法B,則會開啟一個事務。
PROPAGATION_REQURIED_NEW所有方法使用各自的事務,各自提交或者回滾各自的事務,相互之間不會造成影響。
如果嵌套執行的方法要求各自事務獨立,不能進行相互影響,則選擇本事務傳播級別。
執行邏輯
開啟事務
執行方法A的doPreSomething
開啟另一個事務2
執行方法B
提交或者回滾事務2
執行方法A的doSufSomething
提交或回滾事務
3.PROPAGATION_SUPPORTS
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_SUPPORTS)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_SUPPORTS的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B會直接加入方法A的事務中執行,這樣如果在執行方法B的時候出了異常導致事務回滾,則B的方法和A的方法都會回滾。如果A的doPreSomething()和方法B都執行成功了,但是在執行doSufSomething()方法的時候拋出了異常導致事務回滾,則doSufSomething()、methodB()和doPreSomething()都會回滾。
如果不通過方法A而單獨調用方法B,則方法B不會開啟事務,直接會以非事務的方式執行。
PROPAGATION_SUPPORTS如果存著事務就加入和PROPAGATION_REQUIRED傳播級別一致,如果當前不存在事務,則不會創建新的事務,以非事務的方式執行。
如果嵌套執行的方法要求一起執行成功或者一起回滾,單獨執行時候以非事務方式執行,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
執行方法B
執行方法A的doSufSomething
提交或回滾事務
4.PROPAGATION_NOT_SUPPORTED
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_NOT_SUPPORTED)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_NOT_SUPPORTED的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B不允許在事務內部執行,這時候事務就會掛起,在非事務的狀態中執行方法B,不管方法B是執行成功還是執行失敗,都不會對當前事務造成影響。如果A的doPreSomething()和方法B都執行成功了,但是在執行doSufSomething()方法的時候拋出了異常導致事務回滾,則doSufSomething()和doPreSomething()會回滾,而方法B不會受到任何影響,因為它是在非事務中執行的。
如果不通過方法A而單獨調用方法B,則方法B不會開啟事務,直接會以非事務的方式執行。
PROPAGATION_NOT_SUPPORTED如果存著事務就掛起當前事務,以非事務的方式運行自己,如果當前不存在事務,則不會創建新的事務,以非事務的方式執行。
如果嵌套執行的方法要求內部嵌套方法不會對外部方法事務造成影響並且內部方法不需要事務,單獨執行時候以非事務方式執行,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
掛起事務
執行方法B
重新啟用掛起的事務
執行方法A的doSufSomething
提交或回滾事務
5.PROPAGATION_MANDATORY
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_MANDATORY)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_MANDATORY的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B會直接加入方法A的事務中執行,這樣如果在執行方法B的時候出了異常導致事務回滾,則B的方法和A的方法都會回滾。如果A的doPreSomething()和方法B都執行成功了,但是在執行doSufSomething()方法的時候拋出了異常導致事務回滾,則doSufSomething()、methodB()和doPreSomething()都會回滾。
如果不通過方法A而單獨調用方法B,則方法B會直接報錯,因為方法B的事務傳播級別是PROPAGATION_MANDATORY,而其不允許在沒有事務的環境下執行。
PROPAGATION_SUPPORTS如果存著事務就加入和PROPAGATION_REQUIRED傳播級別一致,如果當前不存在事務,會直接進行報錯,不允許以非事務的方式執行。
如果嵌套執行的方法要求一起執行成功或者一起回滾,單獨執行時候不允許以非事務方式執行,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
執行方法B
執行方法A的doSufSomething
提交或回滾事務
6.PROPAGATION_NEVER
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_NEVER)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_NERVR的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B的傳播級別為PROPAGATION_NEVER,其不允許在事務內部執行,所以這時候就會直接報錯。
如果不通過方法A而單獨調用方法B,則方法B會直接在沒有事務的環境中執行。
PROPAGATION_NERVER如果存著事務就直接報錯,如果當前不存在事務,會以非事務的方式執行。
如果嵌套執行的方法要求內部方法不允許在事務中執行,單獨執行時候必須以非事務方式執行,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
執行方法B,直接報錯
回滾事務
7.PROPAGATION_NESTED
@Transactional(propagation=PROPAGATION_REQUIRED)
pubilc void methodA(){
doPreSomething;
methodB();
doSufSomething;
}
@Transactional(propagation=PROPAGATION_NESTED)
pubilc void methodB(){
doSomething;
}
在事務的隔離級別是PROPAGATION_NESTED的時候。
如果調用方法A,會開啟一個事務,在方法A內部調用方法B,由於方法A已經存在開啟尚未提交的事務,方法B的傳播級別為PROPAGATION_NESTED,會加入這個事務當中,但是在執行到方法B之前會創建一個事務的回滾點(savepoint),然後執行方法B,如果方法B執行失敗了,事務會進行回滾,但是這時指揮回滾到回滾點,也就是之後回滾B的操作,外部方法的操作不會回滾;如果B執行成功了,接著執行A的doSufSomething()方法,如果執行出錯,則會回滾整個事務,也就是doSufSomething()、methodB()和doPreSomething()的執行都會進行回滾。
如果直接調用方法B,則會開啟一個事務,和PROPAGATION_REQUIRED傳播級別一致。
如果嵌套執行的方法要求內部方法出錯只回滾自己,外部方法執行失敗回滾所有,單獨執行時候自動開啟一個執行,則選擇該事物傳播級別。
執行邏輯:
開啟事務
執行方法A的doPreSomething
創建回滾點savepoint
執行方法B,失敗只回滾到savepoint
執行方法A的doSufSomething
提交或回滾事務
三、總結
1、PROPAGATION_REQUIRED
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 全部回滾 |
methodB | A內部直接加入事務,不單獨開啟,單獨調用開啟 | 失敗 | 全部回滾 |
doSufSomething | 失敗 | 全部回滾 |
所有方法在同一個事務中運行,要麼一起成功提交事務,要麼一起回滾事務,如果單獨執行,各自單獨開啟各自事務。
2、PROPAGATION_REQUIRED_NEW
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 只回滾方法A自己 |
methodB | 開啟事務 | 失敗 | 只回滾方法B自己 |
doSufSomething | 失敗 | 值回滾方法A自己 |
PROPAGATION_REQURIED_NEW所有方法使用各自的事務,各自提交或者回滾各自的事務,相互之間不會造成影響。
如果嵌套執行的方法要求各自事務獨立,不能進行相互影響,則選擇本事務傳播級別。
3、PROPAGATION_SUPPORTS|
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 全部回滾 |
methodB | A內部加入事務不單獨開啟,單獨調用不開啟 | 失敗 | 全部回滾 |
doSufSomething | 失敗 | 全部回滾 |
如果嵌套執行的方法要求一起執行成功或者一起回滾,單獨執行時候以非事務方式執行,則選擇該事物傳播級別。
4、PROPAGATION_NOT_SUPPORTED
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 只回滾A自己 |
methodB | A內部掛起A的事務狀態執行事務以非,不單獨開啟,單獨調用不開啟 | 失敗 | 不做任何回滾 |
doSufSomething | 失敗 | 只回滾A自己 |
如果嵌套執行的方法要求內部嵌套方法不會對外部方法事務造成影響並且內部方法不需要事務,單獨執行時候以非事務方式執行,則選擇該事物傳播級別。
5、PROPAGATION_MANDATORY
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 全部回滾 |
methodB | A內部加入A的事務,不單獨開啟,單獨調用跑錯 | 失敗 | 全部回滾 |
doSufSomething | 失敗 | 全部回滾 |
如果嵌套執行的方法要求一起執行成功或者一起回滾,單獨執行時候不允許以非事務方式執行,則選擇該事物傳播級別。
6、PROPAGATION_NEVER
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 全部回滾 |
methodB | A存著事務直接拋錯,不單獨開啟 | 失敗 | 全部回滾 |
doSufSomething | 失敗 | 全部回滾 |
如果嵌套執行的方法要求內部方法不允許在事務中執行,單獨執行時候必須以非事務方式執行,則選擇該事物傳播級別。
7、PROPAGATION_NESTED
方法 | 是否開啟事務 | 狀態 | 是否回滾 |
---|---|---|---|
doPreSomething | 開啟事務 | 失敗 | 全部回滾 |
methodB | A存著事務就直接加入A事務,不存在開啟事務 | 失敗 | 只回滾B自己 |
doSufSomething | 失敗 | 全部回滾 |
如果嵌套執行的方法要求內部方法出錯只回滾自己,外部方法執行失敗回滾所有,單獨執行時候自動開啟一個執行,則選擇該事物傳播級別。