@Transactional 是 Spring 提供用来控制事务回滚/提交的一个注解,让我们从编程式注解转换到声明式注解,使用层面不在本章讨论。如果使用不当会造成失效的情况,通过查阅资料和梳理,我总结了如下:

1. 非Public方法

          如果某个方法是private的,那么@Transactional就会失效,因为底层cglib是基于父子类来实现的,子类是不能重载父类的private方法,所以无法很好利用代理,这种情况下会导致@Transactional 注解失效。

2. 数据库本身不支持事务

        这个很好解释,Spring事务管理器管理的是数据库事务,不存在就没有啦。

3. trycatch捕获异常后没有再抛出异常

@Transactional
public void insert(Entity entity){
   try{
       
       baseMapper.insert(entity);
       int i = 1 / 0; //模拟异常
    }catch(Exception e) {
        // 
    }
}

这点小伙伴应该一眼顶真,开发要注意避免这样的低级错误哦~

4. 代理对象调用问题

       因为Spring事务是基于代理来实现的,所以某个加了@Transactional的方法只有是被代理对象调用时,那么这个注解才会生效,所以当被代理对象来调用这个方法那么事务就不会生效。

上代码

public class ServiceExample{

    public void insertA(Entity entity){
        this.insertB(entity);
    }



    @Transactional
    public void insertB(Entity entity){
        baseMapper.insert(entity);
    }


}

   在自身类中用this 调用 带有事务注解的方法,被调用的方法事务无效。

   破解大法 : 拿到代理对象。 

   启动类加上@EnableAspectJAutoProxy(exposeProxy = true)来暴露AOP的Proxy对象才行,否则会报异常。

public class ServiceExample{

    public void insertA(Entity entity){
        ServiceExample proxy = (ServiceExample) AopContext.currentProxy();
        this.insertB(proxy.insertB());
    }



    @Transactional
    public void insertB(Entity entity){
        baseMapper.insert(entity);
    }


}

5. @Transactional 注解属性 propagation 设置错误

若是错误的配置以下三种 propagation ,事务将不会发生回滚

  1. TransactionDefinition.PROPAGATION_SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  3. TransactionDefinition.PROPAGATION_NEVER以非事务方式运行,如果当前存在事务,则抛出异常。

6. @Transactional 注解属性 rollbackFor 设置错误 

  rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。