Spring中propagation的7種事務配置及說明
Spring propagation7種事務配置
1、簡述
在聲明式的事務處理中,要配置一個切面,其中就用到瞭propagation,表示打算對這些方法怎麼使用事務,是用還是不用,其中propagation有七種配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默認是REQUIRED。
2、Spring中七種Propagation類的事務屬性詳解:
REQUIRED
:支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
SUPPORTS
:支持當前事務,如果當前沒有事務,就以非事務方式執行。
MANDATORY
:支持當前事務,如果當前沒有事務,就拋出異常。
REQUIRES
_NEW:新建事務,如果當前存在事務,把當前事務掛起。
NOT_SUPPORTED
:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
NEVER
:以非事務方式執行,如果當前存在事務,則拋出異常。
NESTED
:支持當前事務,如果當前事務存在,則執行一個嵌套事務,如果當前沒有事務,就新建一個事務。
3、註意事項
這些配置將影響數據存儲,必須根據情況選擇。
@Transactional事務幾點註意及其屬性Propagation的使用
@Transactional事務幾點註意
這裡面有幾點需要大傢留意:
A. 一個功能是否要事務,必須納入設計、編碼考慮。不能僅僅完成瞭基本功能就ok。
B. 如果加瞭事務,必須做好開發環境測試(測試環境也盡量觸發異常、測試回滾),確保事務生效。
C. 以下列瞭事務使用過程的註意事項,請大傢留意。
1. 不要在接口上聲明@Transactional ,而要在具體類的方法上使用 @Transactional 註解,否則註解可能無效。
2.不要圖省事,將@Transactional放置在類級的聲明中,放在類聲明,會使得所有方法都有事務。故@Transactional應該放在方法級別,不需要使用事務的方法,就不要放置事務,比如查詢方法。否則對性能是有影響的。
3.使用瞭@Transactional的方法,對同一個類裡面的方法調用, @Transactional無效。比如有一個類Test,它的一個方法A,A再調用Test本類的方法B(不管B是否public還是private),但A沒有聲明註解事務,而B有。則外部調用A之後,B的事務是不會起作用的。(經常在這裡出錯)
4.使用瞭@Transactional的方法,隻能是public,@Transactional註解的方法都是被外部其他類調用才有效,故隻能是public。道理和上面的有關聯。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯,但事務無效。
5.經過在ICORE-CLAIM中測試,效果如下:
A.拋出受查異常XXXException,事務會回滾。
B.拋出運行時異常NullPointerException,事務會回滾。
C.Quartz中,execute直接調用加瞭@Transactional方法,可以回滾;間接調用,不會回滾。(即上文3點提到的)
D.異步任務中,execute直接調用加瞭@Transactional方法,可以回滾;間接調用,不會回滾。(即上文3點提到的)
E.在action中加上@Transactional,不會回滾。切記不要在action中加上事務。
F.在service中加上@Transactional,如果是action直接調該方法,會回滾,如果是間接調,不會回滾。(即上文3提到的)
G.在service中的private加上@Transactional,事務不會回滾。
其屬性Propagation的使用:
Spring Transaction中有一個很重要的屬性:Propagation。主要用來配置當前需要執行的方法,與當前是否有transaction之間的關系。
我曉得有點兒抽象,這也是為什麼我想要寫這篇博客的原因。看瞭後面的例子,大傢應該就明白瞭。
一、Propagation取值:
REQUIRED
(默認值):在有transaction狀態下執行;如當前沒有transaction,則創建新的transaction;
SUPPORTS
:如當前有transaction,則在transaction狀態下執行;如果當前沒有transaction,在無transaction狀態下執行;
MANDATORY
:必須在有transaction狀態下執行,如果當前沒有transaction,則拋出異常IllegalTransactionStateException;
REQUIRES_NEW
:創建新的transaction並執行;如果當前已有transaction,則將當前transaction掛起;
NOT_SUPPORTED
:在無transaction狀態下執行;如果當前已有transaction,則將當前transaction掛起;
NEVER
:在無transaction狀態下執行;如果當前已有transaction,則拋出異常IllegalTransactionStateException。
二、REQUIRED與REQUIRED_NEW
上面描述的6種propagation屬性配置中,最難以理解,並且容易在transaction設計時出現問題的是REQUIRED和REQURED_NEW這兩者的區別。當程序在某些情況下拋出異常時,如果對於這兩者不夠瞭解,就可能很難發現而且解決問題。
下面我們給出三個場景進行分析:
場景一:
ServiceA.java: public class ServiceA { @Transactional public void callB() { serviceB.doSomething(); } } ServiceB.java public class ServiceB { @Transactional public void doSomething() { throw new RuntimeException("B throw exception"); } }
這種情況下,我們隻需要在調用ServiceA.callB時捕獲ServiceB中拋出的運行時異常,則transaction就會正常的rollback。
場景二
在保持場景一中ServiceB不變,在ServiceA中調用ServiceB的doSomething時去捕獲這個異常,如下:
public class ServiceA { @Transactional public void callB() { try { serviceB.doSomething(); } catch (RuntimeException e) { System.err.println(e.getMessage()); } } }
這個時候,我們再調用ServiceA的callB。程序會拋出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only這樣一個異常信息。原因是什麼呢?
因為在ServiceA和ServiceB中的@Transactional propagation都采用的默認值:REQUREID。
根據我們前面講過的REQUIRED特性,當ServiceA調用ServiceB的時候,他們是處於同一個transaction中。
如下圖所示:
當ServiceB中拋出瞭一個異常以後,ServiceB會把當前的transaction標記為需要rollback。
但是ServiceA中捕獲瞭這個異常,並進行瞭處理,認為當前transaction應該正常commit。
此時就出現瞭前後不一致,也就是因為這樣,拋出瞭前面的UnexpectedRollbackException。
場景三
在保持場景二中ServiceA不變,修改ServiceB中方法的propagation配置為REQUIRES_NEW,如下:
public class ServiceB { @Transactional(propagation = Propagation.REQUIRES_NEW) public void doSomething() { throw new RuntimeException("B throw exception"); } }
此時,程序可以正常的退出瞭,也沒有拋出UnexpectedRollbackException。原因是因為當ServiceA調用ServiceB時,serviceB的doSomething是在一個新的transaction中執行的。
如下圖所示:
所以,當doSomething拋出異常以後,僅僅是把新創建的transaction rollback瞭,而不會影響到ServiceA的transaction。
ServiceA就可以正常的進行commit。
當然這裡把ServiceA和ServiceB放在兩個獨立的transaction是否成立,還需要再多多考慮你的業務需求。
Transaction不是一個新東西瞭,那對於transaction的使用會不會有一些模式?一些經驗之談呢?答案肯定是有的,以後再說。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 老生常談spring的事務傳播機制
- 關於Spring的@Transaction導致數據庫回滾全部生效問題(又刪庫跑路)
- Spring事務註解@Transactional失效的八種場景分析
- springboot中使用@Transactional註解事物不生效的坑
- Spring的嵌套事務(Propagation.NESTED)到底是個啥案例代碼講解