原创

SpringBoot学习示例——主动回滚,@Transactional注解捕获异常事务回滚,开发人员根据业务情况主动回滚

1. 不便利的@Transactional

我们在事务的开发中,会将常用的逻辑放在一个事务中,如果这个逻辑常用还好说,如果不常用的话就没必要单独拆出来放在另外的一个方法中,于是这种场景,@Transactional就没办法做到方法中的某个节点进行回滚。

若是拆成单独的事务方法,又没太大必要。

2. try...catch让@Transactional失效

正常情况下加注解@Transactional和try catch捕获异常会让注解失效。

我们开发的时候,也会出错,但是没必要全部回滚,就需要回滚到某个节点,@Transactional注解就无法满足我们这样的需求,那对于开发人员来说,就需要更好的解决方案。

3. 解决方案

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
使用这段代码,就能解决抛出的异常没有被@Transactional捕获异常的问题。因为有些异常我们是需要自己处理的。

    @Transactional(rollbackFor = Exception.class)
    public String fun() {

        ......service1......
        try {
            userMapper.delete(3);
            User user = new User();
            user.setId(2);
            user.setName("jack");
            userMapper.update(user);

            int i = 1/0;
            return "success";
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 
        }
        //其他服务逻辑
        ......service3......

    }

如果像上面代码逻辑中,service1和service2之间的逻辑失败回滚了,但是会将service1的数据变更回滚掉,那如果我们不想回滚service1逻辑,继续执行service3,对于这种场景,上面的方式就没办法解决。
如果回滚可以回到某个节点,而且开发人员自己控制节点,那这样的需求就能完美解决,具体实现方式参考如下代码。

    @Transactional(rollbackFor = Exception.class)
    public String fun() {

        ......service1......
        Object object = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
        try {
            userMapper.delete(3);
            User user = new User();
            user.setId(2);
            user.setName("jack");
            userMapper.update(user);

            int i = 1/0;
            return "success";
        } catch (Exception e) {

            TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
            return e.getMessage();
        }
        //其他服务逻辑
        ......service3......

    }

这里,我们在service1后打一个savepoint回滚点,如果出现问题,就回滚到这个savepoint,再继续执行后续的service3逻辑。

完美解决!

alt

正文到此结束
本文目录