Spring中七種事務(wù)傳播機(jī)制詳解
一、概述
Spring在TransactionDefinition接口中規(guī)定了7種類型的事務(wù)傳播行為。
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(默認(rèn)機(jī)制):如果當(dāng)前存在事務(wù),那么就加入這個(gè)事務(wù),不存在就新建一個(gè)事務(wù)。
- Propagation.SUPPORTS:如果當(dāng)前有事務(wù),加入事務(wù),如果沒有則不使用事務(wù)
- Propagation.MANDATORY:使用當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常
- Propagation.REQUIRES_NEW:新建新的事務(wù),如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起
- Propagation.NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起
- Propagation.NEVER:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就拋出異常
- Propagation.NESTED:如果當(dāng)前存在事務(wù),則嵌套在事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行Propagation.REQUIRED類似操作
1.3 分類舉例
| 傳播機(jī)制 | 解釋 |
| Propagation.NEVER | 非事務(wù)執(zhí)行操作,存在事務(wù),拋出異常 |
| Propagation.MANDATORY | 使用當(dāng)前事務(wù),沒有事務(wù),拋出異常 |
代碼案例:
//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 存在事務(wù) NEVER");
}
@Override
public void test3() {
System.out.println("test3 沒有事務(wù)");
}
}
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 存在事務(wù) REQUIRED");
//如果在調(diào)用NEVER類型的時(shí)候,一定要用這種代理的方式,NEVER才會(huì)生效
testService2.test2();
}
@Override
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
public void test4() {
System.out.println("test4 存在事務(wù) MANDATORY");
testService2.test3();
}
}測試結(jié)果
Propagation.NEVER

Propagation.MANDATORY

| 傳播機(jī)制 | 解釋 |
| Propagation.REQUIRED | 需要在事務(wù)中執(zhí)行,外層有事務(wù)就加入,沒有事務(wù)就自己創(chuàng)建一個(gè)事務(wù) |
| Propagation.REQUIRES_NEW | 需要在一個(gè)新的事務(wù)中執(zhí)行,這個(gè)事務(wù)獨(dú)立于外層的事務(wù),互不影響 |
Propagation.REQUIRES_NEW案例
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void test5() {
System.out.println("當(dāng)前事務(wù) REQUIRED ");
Test test = new Test();
test.setUserName("上海");
test.setAddress("中國");
getBaseMapper().insert(test);
//test6用REQUIRES_NEW修飾,里面有異常,那么當(dāng)前的事務(wù)也會(huì)回滾,如果test5有異常,test6不會(huì)受到影響
testService2.test6();
//當(dāng)前事務(wù)進(jìn)行回滾,test6內(nèi)容會(huì)正常增加
int i = 1/0;
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public void test6() {
System.out.println("創(chuàng)建了一個(gè)新的事務(wù)");
Test test = new Test();
test.setUserName("廣州");
test.setAddress("中國");
getBaseMapper().insert(test);
}注意點(diǎn):
REQUIRES_NEW如果在內(nèi)層,它里面的事務(wù)獨(dú)立于外層的事務(wù),外層事務(wù)如果發(fā)送異?;貪L跟REQUIRES_NEW里面內(nèi)容無關(guān),如果REQUIRES_NEW里面內(nèi)容回滾,那么外層的事務(wù)也會(huì)跟著回滾。
Propagation.REQUIRES_NEW測試結(jié)果

| 傳播機(jī)制 | 解釋 |
| Propagation.SUPPORTS | 外層有事務(wù)就加入,如果沒有事務(wù),就以非事務(wù)方式執(zhí)行 |
| Propagation.NOT_SUPPORTED | 以非事務(wù)的方式執(zhí)行,執(zhí)行的時(shí)候,先將外層的事務(wù)掛起,允許外層有事務(wù)。 |
| 傳播機(jī)制 | 解釋 |
| Propagation.NESTED | 嵌套事務(wù),它是已經(jīng)存在事務(wù)的真正子事務(wù),嵌套事務(wù)開始執(zhí)行時(shí),會(huì)取得一個(gè)保存點(diǎn)(savepoint),如果這個(gè)嵌套事務(wù)失敗,將會(huì)回滾導(dǎo)這個(gè)保存點(diǎn)(savepoint),而不是整個(gè)事務(wù)的回滾 |
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void test7() {
System.out.println("當(dāng)前事務(wù) REQUIRED ");
Test test = new Test();
test.setUserName("上海");
test.setAddress("中國");
getBaseMapper().insert(test);
//NESTED事務(wù)如果進(jìn)行回滾,但是不會(huì)對它外層的事務(wù)造成影響
try{
testService2.test8();
}catch (Exception e){
}
}
@Override
@Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
public void test8() {
System.out.println("創(chuàng)建了一個(gè)新的子事務(wù)");
Test test = new Test();
test.setUserName("廣州");
test.setAddress("中國");
getBaseMapper().insert(test);
int i = 1/0;
}二、總結(jié)
2.1 REQUIRED,REQUIRES_NEW,NESTED
| 狀態(tài) | REQUIRES_NEW(兩個(gè)獨(dú)立事務(wù)) | NESTED(B事務(wù)嵌套在A事務(wù)中) | REQUIRED同一個(gè)事務(wù) |
| 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
- 假設(shè)在A?法存在?個(gè)當(dāng)前事務(wù),B?法的事務(wù)傳播機(jī)制為REQUIRED,則B?法會(huì)合并到A?法的事務(wù)?執(zhí)?。
- A、B任意?個(gè)?法異常(默認(rèn)是RuntimeException和Error)都會(huì)導(dǎo)致A、B的操作被回滾。
- Spring事務(wù)管理器不會(huì)吞異常。
- B異常后會(huì)拋給A,A如果沒有catch這個(gè)異常,會(huì)繼續(xù)向上拋。如果A catch住了,Spring事務(wù)管理器會(huì)替A向上拋?個(gè)
- UnexpectedRollbackException??傊?,?旦A、B回滾,A的調(diào)???定能收到?個(gè)異常感知到回滾。(問題所在)
REQUIRES_NEW
- 如果B發(fā)?異常,B事務(wù)?定回滾,B的異常隨后會(huì)拋給A,如果A catch住了這個(gè)異常,A不會(huì)回滾,否則A也會(huì)回滾。
- 如果A發(fā)?異常,則只會(huì)回滾A,不會(huì)回滾B。
NESTED
- 如果B異常,B?定回滾,B的異常隨后會(huì)拋給A,如果A catch住了這個(gè)異常,A不會(huì)回滾,否則A也會(huì)回滾。這種情況和REQUIRES_NEW?樣。
- 如果A發(fā)?異常,則A、B都會(huì)回滾。
2.3 手動(dòng)回滾
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void test7() {
System.out.println("當(dāng)前事務(wù) REQUIRED ");
Test test = new Test();
test.setUserName("上海");
test.setAddress("中國");
getBaseMapper().insert(test);
//NESTED事務(wù)如果進(jìn)行回滾,但是不會(huì)對它外層的事務(wù)造成影響
try{
testService2.test8();
}catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}到此這篇關(guān)于Spring中七種事務(wù)傳播機(jī)制詳解的文章就介紹到這了,更多相關(guān)Spring事務(wù)傳播機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合ZXing實(shí)現(xiàn)二維碼和條形碼的創(chuàng)建
如今我們越來越多的東西需要用到二維碼或者條形碼,商品的條形碼,付款的二維碼等等,所以本文小編給大家介紹了SpringBoot整合ZXing實(shí)現(xiàn)二維碼和條形碼的創(chuàng)建,文章通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
Spring Boot中使用Redis做緩存的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Spring Boot中使用Redis做緩存的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-06-06
Java生成10個(gè)1000以內(nèi)的隨機(jī)數(shù)并用消息框顯示數(shù)組內(nèi)容然后求和輸出
這篇文章主要介紹了Java生成10個(gè)1000以內(nèi)的隨機(jī)數(shù)并用消息框顯示數(shù)組內(nèi)容然后求和輸出,需要的朋友可以參考下2015-10-10
Zookeeper如何實(shí)現(xiàn)分布式服務(wù)配置中心詳解
Zookeeper在實(shí)際使用場景很多,比如配置中心,分布式鎖,注冊中心等,下面這篇文章主要給大家介紹了關(guān)于Zookeeper如何實(shí)現(xiàn)分布式服務(wù)配置中心的相關(guān)資料,需要的朋友可以參考下2021-11-11
Spring6.x對調(diào)度和異步執(zhí)行的注解支持示例詳解
這篇文章主要為大家介紹了Spring6.x對調(diào)度和異步執(zhí)行的注解支持示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Java class文件格式之屬性_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
在本文中, 主要講解了class文件中的一些屬性。 這些屬性可以出現(xiàn)在class文件中的對個(gè)地方, 用來描述一些其他信息2017-06-06
MyBatis-Plus中自動(dòng)填充功能的用法示例詳解
有些時(shí)候我們可能會(huì)有這樣的需求,插入或者更新數(shù)據(jù)時(shí),希望有些字段可以自動(dòng)填充數(shù)據(jù),比如密碼、version、注冊時(shí)默認(rèn)的用戶角色等,在MP中提供了這樣的功能,可以實(shí)現(xiàn)自動(dòng)填充功能,需要的朋友可以參考下2022-12-12
使用JVMTI實(shí)現(xiàn)SpringBoot的jar加密,防止反編譯
這篇文章主要介紹了使用JVMTI實(shí)現(xiàn)SpringBoot的jar加密,防止反編譯問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08

