Spring中七种事务传播机制详解

 更新时间:2024年01月17日 10:21:50   作者:java-zh  
这篇文章主要介绍了Spring中七种事务传播机制详解,Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,Propagation枚举则引用了这些类型,开发过程中我们一般直接用Propagation枚举,需要的朋友可以参考下

一、概述

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。

Propagation枚举则引用了这些类型,开发过程中我们一般直接用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:以非事务方式执行操作,如果当前存在事务,把当前事务挂起
  • Propagation.NEVER:以非事务方式执行操作,如果当前存在事务,就抛出异常
  • Propagation.NESTED:如果当前存在事务,则嵌套在事务内执行。如果当前没有事务,则执行Propagation.REQUIRED类似操作

1.3 分类举例

传播机制解释
Propagation.NEVER非事务执行操作,存在事务,抛出异常
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需要在事务中执行,外层有事务就加入,没有事务就自己创建一个事务
Propagation.REQUIRES_NEW需要在一个新的事务中执行,这个事务独立于外层的事务,互不影响

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("创建了一个新的事务");
        Test test = new Test();
        test.setUserName("广州");
        test.setAddress("中国");
        getBaseMapper().insert(test);
    }

注意点:

REQUIRES_NEW如果在内层,它里面的事务独立于外层的事务,外层事务如果发送异常回滚跟REQUIRES_NEW里面内容无关,如果REQUIRES_NEW里面内容回滚,那么外层的事务也会跟着回滚。

Propagation.REQUIRES_NEW测试结果

传播机制解释
Propagation.SUPPORTS外层有事务就加入,如果没有事务,就以非事务方式执行
Propagation.NOT_SUPPORTED以非事务的方式执行,执行的时候,先将外层的事务挂起,允许外层有事务。
传播机制解释
Propagation.NESTED        嵌套事务,它是已经存在事务的真正子事务,嵌套事务开始执行时,会取得一个保存点(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("创建了一个新的子事务");
        Test test = new Test();
        test.setUserName("广州");
        test.setAddress("中国");
        getBaseMapper().insert(test);
        int i = 1/0;
    }

二、总结

2.1 REQUIRED,REQUIRES_NEW,NESTED

状态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⽅法的事务⾥执⾏。
  • A、B任意⼀个⽅法异常(默认是RuntimeException和Error)都会导致A、B的操作被回滚。
  • Spring事务管理器不会吞异常。
  • B异常后会抛给A,A如果没有catch这个异常,会继续向上抛。如果A catch住了,Spring事务管理器会替A向上抛⼀个
  • UnexpectedRollbackException。总之,⼀旦A、B回滚,A的调⽤⽅⼀定能收到⼀个异常感知到回滚。(问题所在)

REQUIRES_NEW

  • 如果B发⽣异常,B事务⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。
  • 如果A发⽣异常,则只会回滚A,不会回滚B。

NESTED

  • 如果B异常,B⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。这种情况和REQUIRES_NEW⼀样。
  • 如果A发⽣异常,则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事务传播机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java网络编程基础教程之Socket入门实例

    Java网络编程基础教程之Socket入门实例

    这篇文章主要介绍了Java网络编程基础教程之Socket入门实例,本文讲解了创建Socket、Socket发送数据、Socket读取数据、关闭Socket等内容,都是最基础的知识点,需要的朋友可以参考下
    2014-09-09
  • Gradle jvm插件系列教程之Java Library插件权威详解

    Gradle jvm插件系列教程之Java Library插件权威详解

    这篇文章主要介绍了Java Library插件权威详解,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • Mybatis联合查询的实现方法

    Mybatis联合查询的实现方法

    本文主要介绍了 Mybatis联合查询的实现方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • SpringAOP 设置注入的实现步骤

    SpringAOP 设置注入的实现步骤

    这篇文章主要介绍了SpringAOP 设置注入的实现步骤,帮助大家更好的理解和学习使用Spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • Mybatis Plus LambdaQueryWrapper的具体用法

    Mybatis Plus LambdaQueryWrapper的具体用法

    Mybatis Plus 在其基础上扩展了 LambdaQueryWrapper,LambdaQueryWrapper 提供了更加简便的查询语法,同时也避免了SQL注入的风险,感兴趣的可以了解一下
    2023-11-11
  • 关于springboot的接口返回值统一标准格式

    关于springboot的接口返回值统一标准格式

    这篇文章主要介绍了关于springboot的接口返回值统一标准格式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Java线程中的用户态和内核态解读

    Java线程中的用户态和内核态解读

    这篇文章主要介绍了Java线程中的用户态和内核态解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • java数据结构和算法学习之汉诺塔示例

    java数据结构和算法学习之汉诺塔示例

    这篇文章主要介绍了java数据结构和算法中的汉诺塔示例,需要的朋友可以参考下
    2014-02-02
  • 探索分析Redis AOF日志与数据持久性

    探索分析Redis AOF日志与数据持久性

    这篇文章主要为大家介绍了探索分析Redis AOF日志与数据持久性详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Java TreeSet 添加失败的解决

    Java TreeSet 添加失败的解决

    这篇文章主要介绍了Java TreeSet 添加失败的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09

最新评论