Spring事务传播机制--包含用例解释

Spring事务传播机制
一、何为Spring传播机制:

Spring事务的传播机制就是,事务如何在方法的调用如何传播。

二、使用传播机制的时候的关键点:
  • 使用声明式的事务时,调用方法和被调用方法不能在同一个类。比如同在一个service方法中,这样是不会生效的。Spring的事务分为编程式和声明式的注解,我们一般使用声明方式的注解,利用@Transactional注解标记需要使用事务的类,Spring会利用AOP为我们在方法执行前启动事务,接受后提交和关闭事务。而AOP是基于动态代理的实现,生成代理对象,调用代理对象实现事务,而在同一个类中的调用,就会在这个类的对象调用this.method(),没有用到代理,也不会有事务。

  • 使用Spring事务的方法需要被Spring所管理。不然Spring无法通过AOP生成事务。

  • 确保Spring开启事务支持。

三、理解事务传播机制的角度(个人见解)

刚开始,学习这个Spring事务传播机制的时候,一直纠结调用方法和被调用存在事务这一概念。其实如果从被调用的角度看存在和不存在事务,就能很好的理解这些传播机制。通过下面一些测试,我先猜想结果,在验证结果,也能证实自己是否理解了Spring事务的传播。

四、Spring事务传播的七种方式

ps:测试其中方式的例子都是同一个,就是一个用户修改方法,修改用户名称;一个插入修改日志的方法,插入修改日志,在修改方法内调用插入日志的方法,目的是让两个数据库操作具有原子性,所以应用事务。同时利用除数为0创造异常,更好的测试。

一、REQUIRE
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        int i = 10 / 0;
    }

两个方法都是才有默认的事务传播属性Propagation.REQUIRED

Propagation.REQUIRED:如果当前存在事务,那么就加入这个事务,不存在就新建一个事务。

结果:这里也是两个方法都没有将操作成功,因为REQUIRE的事务传播机制下,调用者存在了一个事务,被调用者在已经存在事务的情况下,加入调用者这个事务,而不自己新创建,所以两者在同一事务种,被调用方法发生异常,整个事务回滚,都不操作成功。

SUPPORTS

Propagation.SUPPORTS:如果当前有事务,加入事务,如果没有则不使用事务

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        int i = 10 / 0;
    }

调用方法的传播属性是Propagation.REQUIRED,被调用的是Propagation.SUPPORTS

结果:这里也是两个方法都没有将数据操作成功–用户名称没有修改,修改日志也没有插入,发生了异常,两个数据操作都回滚了。因为调用方法存在事务,而被调用方法可以支持事务,有则加入到这个事务中,所以两方法处于同一事务,有异常则两者都回滚。

   @Override
   // @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
    }
    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        int i = 10 / 0;
    }

调用方法的没有事务,被调用的是Propagation.SUPPORTS

结果:这里也是两个方法都将数据操作成功–用户名称修改,修改日志也插入即使有异常,因为SUPPORTS没有处在事务中,所以被调用方法也没使用事务执行,即使有异常也没有回滚

三、NOT_SUPPORTED

NOT_SUPPORTED:表示不支持事务,如果有事务也不加入事务,没有事务以非事务运行

  @Override
//    @Transactional(rollbackFor = ArithmeticException.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        saveLog(user.getId());
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = ArithmeticException.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        int i = 10 / 0;
    }

调用方法没有事务,被调用的是pagation = Propagation.NOT_SUPPORTED

结果:调用方法没有事务,被调用方法不支持事务,即使报错,数据库都操作成功。

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
        //调用方发生异常
        int i = 10 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        int i = 10 / 0;
    }

调用方法的传播属性是Propagation.REQUIRED,被调用的是pagation = Propagation.NOT_SUPPORTED,且调用方法发生异常,被调用方法也发生异常。

结果:调用方法没有操作数据库成功,因为REQUIRED新建了一个新的事务,发生异常回滚。但是被调用方法操作数据库成功,因为NOT_SUPPOTS不支持事务,即使存在事务也不加入,所以即使有异常,也不回滚。

四、REQUIRES_NEW

REQUIRES_NEW:不管是否存在事务,都以最新的事务执行,执行完在执行旧的事务

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
        int i = 10 / 0;
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
    }
}

调用方法的传播属性是Propagation.REQUIRED,被调用方法的是Propagation.REQUIRES_NEW

结果:调用方法操作数据库失败,因为自己所在得事务中有异常,且有事务,操作回滚。被调用操作数据库成功,因为创建了一个新的事务,与已经存在的事务无关,没有异常正常执行,调用方法和被调用方法处于两个不同得事务,因为.REQUIRES_NEW以新的事务执行。

五、MANDATORY

MANDATORY(强制的):必须在一个事务中执行,如果没有事务,则抛出异常

     @Override
    //@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
    }
    @Override
    @Transactional(propagation = Propagation.MANDATORY,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        //int i = 10 / 0;
    }

调用方法没有加入事务,被调用方法使用MANDATORY

结果:调用方法正常执行数据库操作,被调用方法抛出异常,且没有执行数据库操作(异常中断了程序),抛出的异常时因为被调用法必须在事务中执行,没有事务,抛出异常,异常如下:
在这里插入图片描述

六、NEVER

NEVER:以非事务的方式执行,如果存在事务异常

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
    public void updateUserName(String userName) {
        User user = new User();
        user.setId(1);
        user.setUserName(userName);
        userMapper.updateUserName(user);
        userChangeLogService.saveLog(user.getId());
    }
    @Override
    @Transactional(propagation = Propagation.NEVER,rollbackFor = Throwable.class)
    public void saveLog(Integer userId) {
        UserChangeLog userChangeLog = new UserChangeLog();
        userChangeLog.setOpratorUserId(userId);
        userChangeLogMapper.insert(userChangeLog);
        //int i = 10 / 0;
    }

调用方法使用的QEQUIRE,会创建一个新的事务,被调用方法使用NEVER,两个方法都没有额外的异常。

结果:调用方法操作数据库不成功,被调用方法操作数据库不成功。因为被调用方法时NEVER的传播机制,调用方法有事务,被调用方法会抛出异常,导致本身执行不成功,抛出的异常也会导致调用方法的事务回滚,操作不成功。抛出的异常如下:
在这里插入图片描述

七、PROPAGATION_NESTED

PROPAGATION_NESTED:如果调用者不存在事务,那么被调用者自己创建事务,这种情况和REQUIRE一样。如果调用者存在事务,那么被调用者就在调用者的事务里嵌套一个事务,称为嵌套事务。

使用嵌套事务是用条件的:

  • 数据库的支持

  • JDK 1.4 才支持 java.sql.Savepoint 。所以JDK必须在1.4 及以上

  • 还需要Spring中配置nestedTransactionAllowed=true。

回答: Spring事务的传播行为是指在方法调用过程中,事务的行为是如何传播的。根据引用,Spring提供了七种传播行为,其中默认的传播行为是required。这意味着如果当前存在事务,被调用的方法会加入到当前事务中,如果当前没有事务,它们会开启一个新的事务。而如果采用NEVER传播行为,被调用的方法将以非事务方式执行,如果当前存在事务,则抛出异常。而MANDATORY传播行为则要求当前必须存在一个事务,如果当前没有事务,则抛出异常。总的来说,Spring事务传播机制允许我们灵活地控制事务的行为,确保数据一致性。123 #### 引用[.reference_title] - *1* [Spring事务传播机制--包含用例解释](https://blog.csdn.net/qq_45646289/article/details/124882146)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* [Spring事务传播行为](https://blog.csdn.net/m0_73687324/article/details/128255689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *3* [Spring事务传播性(较详细描述)](https://blog.csdn.net/lizhongchao_/article/details/113786943)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值