2022-09-03 事务的思考

在开发中难免会遇到例如转账类似的业务,那么此时最少两步才能完成,扣钱+ 加钱, 就会需要用事务进行控制,防止执行一半发生一半,导致数据错乱,不加以控制将产生严重问题,如 扣钱成功 但是加钱失败,那么扣得钱就找不到了!!!!

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;


   @Override
    @Transactional(rollbackFor = Exception.class)
    public void doSomething(UserDO userDo) {
        insert(userDo);
        doOther();
    }

    @Transactional(propagation =Propagation.REQUIRES_NEW)  // 开启一个新事务
    public void insert(UserDO userDo) {
        userMapper.insert(userDo);
    }

    public void doOther() {
        System.out.println("做一些其它的事,比如调用其它的系统");
    }
}

仔细观察此段代码, 在实现方法上添加了事务 @Transactional 那么也就是一个事务的开启了;
接下来调用了insert方法,可以看到insert方法上也加了事务 @Transactional(propagation =Propagation.REQUIRES_NEW) 并且设置为了 new 开启新事务,那么这里开始了新事务嘛?
=
=
=
=
=
=
=
=
=
=
答案是否定的!!
因为spring默认启用cglib代理,这里由于是实现了接口,那么可以找到这个类的接口,所以是典型的基于invoke方法实现的代理,那么doSomething开启的事务肯定没有问题,但是insert方法仔细观察,它是内部调用,也就是this,并不会有代理,那么这个方法上开启的事务也就不会生效;
@Transactional 的实现原理是AOP,AOP的实现原理是动态代理,换句话说,自调用时不存在代理对象的调用,这时不会产生我们注解@Transactional 配置的参数,自然无效了;insert 方法并没有接口,在实现类里面只是一个简单的方法而已,对于事务的注解来说没有任何作用;

事务失效的几种场景(首先要知道事务是基于aop实现的);
1 接口的实现方法是private final static 等修饰的, 权限问题,导致事务失效
2 方法中有try catch 处理,产生了异常不会自动回滚,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一
下,如:@Transactional(rollbackFor = Exception.class)
3 在一个事务中调用另一个service的方法,并开启了新事物( propagation= REQUIRES_NEW),当调用方出现错误,新事物不会跟随回滚;
4 在同一个service没有@Transactional注解的方法调用带@Transactional的方法,事务不起作用;此方法即使报错,回滚也会失败,因为内部调用,不会有代理对象产生(相当于一个普通的么有加事务的方法想调用rollback,肯定是没有这个方法的 );

你可能感兴趣的:(2022-09-03 事务的思考)