先了解事務的7種傳播屬性:java
PROPAGATION_REQUIRED -- 支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。 PROPAGATION_SUPPORTS -- 支持當前事務,若是當前沒有事務,就以非事務方式執行。 PROPAGATION_MANDATORY -- 支持當前事務,若是當前沒有事務,就拋出異常。 PROPAGATION_REQUIRES_NEW -- 新建事務,若是當前存在事務,把當前事務掛起。 PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。 PROPAGATION_NEVER -- 以非事務方式執行,若是當前存在事務,則拋出異常。 PROPAGATION_NESTED -- 若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則進行與PROPAGATION_REQUIRED相似的操做。 前六個策略相似於EJB CMT,第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。 它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行爲(如Spring的DataSourceTransactionManager)
問題產生場景:spa
1.在 DemoServiceA.java中有方法 demoMethodA().其中嵌套DemoServiceB.java中demoMethodB()。當demoMethodA事務發生rollback時, demoMethodB 事務也能夠rollback或是commit。設計
如圖:code
public class DemoServiceA { public void demoMethodA() { demoServiceB.demoMethodB();//Insert對象B 操做
} }
常看法決方案: 對象
public class DemoServiceA { /** * 新建事務 * 事務屬性配置爲 PROPAGATION_REQUIRED */ @Transactional(propagation=Propagation.REQUIRED) public void demoMethodA() { //操做... /** * 1.事務屬性配置爲 PROPAGATION_REQUIRES_NEW ; * A. DemoServiceA 事務commit與rollback,與 DemoServiceB無任何關係,DemoServiceB 不屬於事務 DemoServiceA的子事務。 * PROPAGATION_REQUIRES_NEW 啓動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被徹底 commited * 或 rolled back 而不依賴於外部事務, 它擁有本身的隔離範圍, 本身的鎖, 當內部事務開始執行時, * 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. * B. 能夠起到分支執行的效果。service方法雖然嵌套可是事務之間狀態相互無影響 * * * * 2.事務屬性配置爲 PROPAGATION_NESTED; * PROPAGATION_NESTED 開始一個 "嵌套的" 事務, 它是已經存在事務的一個真正的子事務. * 潛套事務開始執行時, 它將取得一個 savepoint. 若是這個嵌套事務失敗, * 咱們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它纔會被提交. * */ demoServiceB.demoMethodB();//Insert對象B 操做 //操做... } }
下面詳細介紹7種事務傳播屬性在示例中的做用:blog
1: REQUIRED 加入當前正要執行的事務不在另一個事務裏,那麼就起一個新的事務 好比說,DemoServiceB.demoMethodB的事務級別定義爲REQUIRED, 那麼因爲執行DemoServiceA.demoMethodA的時候, DemoServiceA.demoMethodA已經起了事務,這時調用DemoServiceB.demoMethodB,DemoServiceB.demoMethodB看到本身已經運行在DemoServiceA.demoMethodA 的事務內部,就再也不起新的事務。而假如DemoServiceA.demoMethodA運行的時候發現本身沒有在事務中,他就會爲本身分配一個事務。 這樣,在DemoServiceA.demoMethodA或者在DemoServiceB.demoMethodB內的任何地方出現異常,事務都會被回滾。即便DemoServiceB.demoMethodB的事務已經被 提交,可是DemoServiceA.demoMethodA在接下來fail要回滾,DemoServiceB.demoMethodB也要回滾 2: SUPPORTS 若是當前在事務中,即以事務的形式運行,若是當前再也不一個事務中,那麼就以非事務的形式運行 3: MANDATORY 必須在一個事務中運行。也就是說,他只能被一個父事務調用。不然,他就要拋出異常 4: REQUIRES_NEW 這個就比較繞口了。 好比咱們設計DemoServiceA.demoMethodA的事務級別爲REQUIRED,DemoServiceB.demoMethodB的事務級別爲REQUIRES_NEW, 那麼當執行到DemoServiceB.demoMethodB的時候,DemoServiceA.demoMethodA所在的事務就會掛起,DemoServiceB.demoMethodB會起一個新的事務,等待DemoServiceB.demoMethodB的事務完成之後, 他才繼續執行。他與REQUIRED 的事務區別在於事務的回滾程度了。由於DemoServiceB.demoMethodB是新起一個事務,那麼就是存在 兩個不一樣的事務。若是DemoServiceB.demoMethodB已經提交,那麼DemoServiceA.demoMethodA失敗回滾,DemoServiceB.demoMethodB是不會回滾的。若是DemoServiceB.demoMethodB失敗回滾, 若是他拋出的異常被DemoServiceA.demoMethodA捕獲,DemoServiceA.demoMethodA事務仍然可能提交。 5: NOT_SUPPORTED 當前不支持事務。好比DemoServiceA.demoMethodA的事務級別是REQUIRED ,而DemoServiceB.demoMethodB的事務級別是NOT_SUPPORTED , 那麼當執行到DemoServiceB.demoMethodB時,DemoServiceA.demoMethodA的事務掛起,而他以非事務的狀態運行完,再繼續DemoServiceA.demoMethodA的事務。 6: NEVER 不能在事務中運行。假設DemoServiceA.demoMethodA的事務級別是REQUIRED, 而DemoServiceB.demoMethodB的事務級別是NEVER , 那麼DemoServiceB.demoMethodB就要拋出異常了。 7: NESTED 理解Nested的關鍵是savepoint。他與REQUIRES_NEW的區別是,REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立, 而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,若是父事務最後回滾,他也要回滾的。