Spring中七種事務傳播機制詳解
一、概述
Spring在TransactionDefinition接口中規(guī)定了7種類型的事務傳播行為。
Propagation枚舉則引用了這些類型,開發(fā)過程中我們一般直接用Propagation枚舉。
1.1 Propagation源碼
public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); private final int value; private Propagation(int value) { this.value = value; } public int value() { return this.value; }}public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); private final int value; private Propagation(int value) { this.value = value; } public int value() { return this.value; } }
1.2、類型解析
- Propagation.REQUIRED(默認機制):如果當前存在事務,那么就加入這個事務,不存在就新建一個事務。
- Propagation.SUPPORTS:如果當前有事務,加入事務,如果沒有則不使用事務
- Propagation.MANDATORY:使用當前事務,如果當前沒有事務,就拋出異常
- Propagation.REQUIRES_NEW:新建新的事務,如果當前存在事務,就把當前事務掛起
- Propagation.NOT_SUPPORTED:以非事務方式執(zhí)行操作,如果當前存在事務,把當前事務掛起
- Propagation.NEVER:以非事務方式執(zhí)行操作,如果當前存在事務,就拋出異常
- Propagation.NESTED:如果當前存在事務,則嵌套在事務內執(zhí)行。如果當前沒有事務,則執(zhí)行Propagation.REQUIRED類似操作
1.3 分類舉例
傳播機制 | 解釋 |
Propagation.NEVER | 非事務執(zhí)行操作,存在事務,拋出異常 |
Propagation.MANDATORY | 使用當前事務,沒有事務,拋出異常 |
代碼案例:
//controller @RestController @RequestMapping("/op") public class TestController { @Autowired private TestService testService; @GetMapping("/test1") public void test1() { testService.test1(); } } //service public interface TestService2 extends BaseService<Test> { void test2(); void test3(); } @Service public class TestServiceImpl2 extends BaseServiceImpl<TestMapper, Test> implements TestService2 { @Override @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class) public void test2() { System.out.println("test2 存在事務 NEVER"); } @Override public void test3() { System.out.println("test3 沒有事務"); } } public interface TestService extends BaseService<Test> { int insert(Test test); int update(Test test); void test1(); void test4(); } @Service public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService { @Autowired private TestService2 testService2; @Override public int insert(Test test) { return getBaseMapper().insert(test); } @Override public int update(Test test) { return getBaseMapper().updateById(test); } @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test1() { System.out.println("test1 存在事務 REQUIRED"); //如果在調用NEVER類型的時候,一定要用這種代理的方式,NEVER才會生效 testService2.test2(); } @Override @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class) public void test4() { System.out.println("test4 存在事務 MANDATORY"); testService2.test3(); } }
測試結果
Propagation.NEVER
Propagation.MANDATORY
傳播機制 | 解釋 |
Propagation.REQUIRED | 需要在事務中執(zhí)行,外層有事務就加入,沒有事務就自己創(chuàng)建一個事務 |
Propagation.REQUIRES_NEW | 需要在一個新的事務中執(zhí)行,這個事務獨立于外層的事務,互不影響 |
Propagation.REQUIRES_NEW案例
@Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test5() { System.out.println("當前事務 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中國"); getBaseMapper().insert(test); //test6用REQUIRES_NEW修飾,里面有異常,那么當前的事務也會回滾,如果test5有異常,test6不會受到影響 testService2.test6(); //當前事務進行回滾,test6內容會正常增加 int i = 1/0; } @Override @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class) public void test6() { System.out.println("創(chuàng)建了一個新的事務"); Test test = new Test(); test.setUserName("廣州"); test.setAddress("中國"); getBaseMapper().insert(test); }
注意點:
REQUIRES_NEW如果在內層,它里面的事務獨立于外層的事務,外層事務如果發(fā)送異常回滾跟REQUIRES_NEW里面內容無關,如果REQUIRES_NEW里面內容回滾,那么外層的事務也會跟著回滾。
Propagation.REQUIRES_NEW測試結果
傳播機制 | 解釋 |
Propagation.SUPPORTS | 外層有事務就加入,如果沒有事務,就以非事務方式執(zhí)行 |
Propagation.NOT_SUPPORTED | 以非事務的方式執(zhí)行,執(zhí)行的時候,先將外層的事務掛起,允許外層有事務。 |
傳播機制 | 解釋 |
Propagation.NESTED | 嵌套事務,它是已經存在事務的真正子事務,嵌套事務開始執(zhí)行時,會取得一個保存點(savepoint),如果這個嵌套事務失敗,將會回滾導這個保存點(savepoint),而不是整個事務的回滾 |
@Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test7() { System.out.println("當前事務 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中國"); getBaseMapper().insert(test); //NESTED事務如果進行回滾,但是不會對它外層的事務造成影響 try{ testService2.test8(); }catch (Exception e){ } } @Override @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class) public void test8() { System.out.println("創(chuàng)建了一個新的子事務"); Test test = new Test(); test.setUserName("廣州"); test.setAddress("中國"); getBaseMapper().insert(test); int i = 1/0; }
二、總結
2.1 REQUIRED,REQUIRES_NEW,NESTED
狀態(tài) | 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一起提交 |
2.2 三者不同
REQUIRED
- 假設在A?法存在?個當前事務,B?法的事務傳播機制為REQUIRED,則B?法會合并到A?法的事務?執(zhí)?。
- A、B任意?個?法異常(默認是RuntimeException和Error)都會導致A、B的操作被回滾。
- Spring事務管理器不會吞異常。
- B異常后會拋給A,A如果沒有catch這個異常,會繼續(xù)向上拋。如果A catch住了,Spring事務管理器會替A向上拋?個
- UnexpectedRollbackException??傊?,?旦A、B回滾,A的調???定能收到?個異常感知到回滾。(問題所在)
REQUIRES_NEW
- 如果B發(fā)?異常,B事務?定回滾,B的異常隨后會拋給A,如果A catch住了這個異常,A不會回滾,否則A也會回滾。
- 如果A發(fā)?異常,則只會回滾A,不會回滾B。
NESTED
- 如果B異常,B?定回滾,B的異常隨后會拋給A,如果A catch住了這個異常,A不會回滾,否則A也會回滾。這種情況和REQUIRES_NEW?樣。
- 如果A發(fā)?異常,則A、B都會回滾。
2.3 手動回滾
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test7() { System.out.println("當前事務 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中國"); getBaseMapper().insert(test); //NESTED事務如果進行回滾,但是不會對它外層的事務造成影響 try{ testService2.test8(); }catch (Exception e){ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
到此這篇關于Spring中七種事務傳播機制詳解的文章就介紹到這了,更多相關Spring事務傳播機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot整合ZXing實現二維碼和條形碼的創(chuàng)建
如今我們越來越多的東西需要用到二維碼或者條形碼,商品的條形碼,付款的二維碼等等,所以本文小編給大家介紹了SpringBoot整合ZXing實現二維碼和條形碼的創(chuàng)建,文章通過代碼示例給大家介紹的非常詳細,需要的朋友可以參考下2023-12-12Java生成10個1000以內的隨機數并用消息框顯示數組內容然后求和輸出
這篇文章主要介紹了Java生成10個1000以內的隨機數并用消息框顯示數組內容然后求和輸出,需要的朋友可以參考下2015-10-10Spring6.x對調度和異步執(zhí)行的注解支持示例詳解
這篇文章主要為大家介紹了Spring6.x對調度和異步執(zhí)行的注解支持示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11Java class文件格式之屬性_動力節(jié)點Java學院整理
在本文中, 主要講解了class文件中的一些屬性。 這些屬性可以出現在class文件中的對個地方, 用來描述一些其他信息2017-06-06使用JVMTI實現SpringBoot的jar加密,防止反編譯
這篇文章主要介紹了使用JVMTI實現SpringBoot的jar加密,防止反編譯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08