浅析Spring事务的传播性

  1. 方法A和方法B的事务传播性都为PROPAGATION_REQUIRED
    当方法A调用方法B, 方法B报错, 即使报错被外层捕获, 整体事务也会回滚.报错信息为UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
  • 代码演示

@Override
public void do_transaction_required_required_exception_try(Integer id, String name) {
    this.save(new Users(id, name, null));

    try {
        biaoSuoService.addBiaoSuo(id, name);
    }catch (Exception e){
        log.error("插入记录错误信息", e);
    }
}

@Override
public boolean addBiaoSuo(Integer id, String name) {
    BiaoSuo biaoSuo = new BiaoSuo();
    biaoSuo.setId(id);
    biaoSuo.setName(name);
    super.save(biaoSuo);
    int i = 1;
    if(i == 1){
        throw new RuntimeException("addBiaoSuo方法报错...");
    }
    return true;
}

    @Test
    public void contextLoads() {
        usersService.do_transaction_required_required_exception_try(26, "name26");
    }
  • 测试结果
    在这里插入图片描述
  1. 方法A的事务传播性为PROPAGATION_REQUIRED, 方法B的事务传播性为PROPAGATION_REQUIRES_NEW
    当方法A调用方法B, 方法B报错, 报错被外层捕获时, 新开的事务B回滚, 外层的事务A不会回滚.
  • 代码演示
    @Override
    public void do_transaction_required_requiresNew_exception_try(Integer id, String name) {
        System.out.println("方法是否有事务: " + TransactionSynchronizationManager.isActualTransactionActive());
        this.save(new Users(id, name, null));

        try {
            biaoSuoService.newTl_requiresNew_exception(id, name);
        }catch (Exception e){
            log.error("插入记录错误信息", e);
        }
    }

    @Override
    public boolean newTl_requiresNew_exception(Integer id, String name) {
        BiaoSuo biaoSuo = new BiaoSuo();
        biaoSuo.setId(id);
        biaoSuo.setName(name);
        super.save(biaoSuo);
        log.info("isNewTransaction: [{}]", TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
        int i = 1;
        if(i == 1){
            throw new RuntimeException("addBiaoSuorequiresNew_exception方法报错...");
        }
        return true;
    }

    @Test
    public void test1(){
        usersService.do_transaction_required_requiresNew_exception_try(27, "name27");
    }
  • 测试结果
    在这里插入图片描述
    在这里插入图片描述
  1. 方法A的事务传播性为PROPAGATION_REQUIRED, 方法B的事务传播性为NESTED
    当方法A调用方法B, 方法B报错, 整体事务会回滚. 如果外层捕获方法B的异常, 只有子事务B会回滚, 方法A不会回滚.
  • 代码演示
    @Override
    public void do_transaction_required_nested_exception(Integer id, String name) {
        System.out.println("方法是否有事务: " + TransactionSynchronizationManager.isActualTransactionActive());
        this.save(new Users(id, name, null));

        biaoSuoService.addNestedException(id, name);
    }
    
    @Override
    public boolean addNestedException(Integer id, String name) {
        BiaoSuo biaoSuo = new BiaoSuo();
        biaoSuo.setId(id);
        biaoSuo.setName(name);
        super.save(biaoSuo);
        log.info("hasSavepoint: [{}]", TransactionAspectSupport.currentTransactionStatus().hasSavepoint());
        int i = 1;
        if(i == 1){
            throw new RuntimeException("addNestedException方法报错...");
        }
        return true;
    }

    @Test
    public void test2(){
        usersService.do_transaction_required_nested_exception(29, "name29");
    }
  • 测试结果
    在这里插入图片描述
    在这里插入图片描述
  1. NESTED和REQUIRED的区别与联系
    NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。
  2. NESTED和REQUIRES_NEW的区别与联系
    NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务。
  3. 一般的用法
  • 我能影响你, 但是你不能影响我. 你应该用NESTED, 我应该捕获你的异常.
  • 日志方法应该使用PROPAGATION_NOT_SUPPORTED
  1. 小技巧
  • 事务什么时候会生效?
    service的实现类上有注解, 并且方法名以事务配置中的前缀开头
  • 如何判断某个有没有事务?
    TransactionSynchronizationManager.isActualTransactionActive()
  • 如何获取到当前方法的事务?
    TransactionAspectSupport.currentTransactionStatus();
  • 编程式事务如何实现?
    TransactionTemplate或者PlatformTransactionManager
  • 服务经常报获取不到数据库连接怎么办?
    检查编程式事务有没有提交或回滚事务, 防止数据库连接泄漏.
  • 如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。
  1. 注意事项
  • @Transactional 只能被应用到 public 方法上,对于其它非 public 的方法,如果标记了 @Transactional 也不会报错,但方法没有事务功能。
  • Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
  • 默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值