Springboot事务回滚时报错:No transaction aspect-managed TransactionStatus in scope

5 篇文章 0 订阅

出错原因

  同一个代理类里面,被调用方法有@Transactional注解,而外层防范没有注解

@Override
    public void test1() {
       test2();
    }

    @Transactional
    public void test2(){
        try {
              ... sql操作 ...
              System.out.println(1/0) ;  //抛出异常
        } catch (Exception e) {
            // 发生异常时手动触发事务回滚
          TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

  在上述代码中事务不仅不会回滚,还会报出异常org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope

原因解释

  事实上Spring中的@Transactional原理是通过TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截。像上面的代码,Spring AOP实际上是为每个@Service注解的类生成一个代理类,由于代理类的test1方法没有被注解修饰,Spring认为这里不用事务拦截器进行拦截,即便被调用类中使用了事务注解。

使用注意事项

  • 在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
  • @Transactional 注解应该只被应用在 public 修饰的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 该注解,它也不会报错(IDEA会有提示), 但事务并没有生效。
    a. 被外部调用的公共方法A有两个进行了数据操作的子方法B和子方法C的事务注解说明:
    b.被外部调用的公共方法A未声明事务@Transactional,子方法B和C若是其他类的方法且各自声明事务,则事务由子方法B和C各自控制
    c.被外部调用的公共方法A未声明事务@Transactional,子方法B和C若是本类的方法,则无论子方法B和C是否声明事务,事务均不会生效
    d.被外部调用的公共方法A声明事务@Transactional,无论子方法B和C是不是本类的方法,无论子方法B和C是否声明事务,事务均由公共方法A控制
    被外部调用的公共方法A声明事务@Transactional,子方法运行异常,但运行异常被子方法自己 try-catch 处理了,则事务回滚是不会生效的!

  如果想要事务回滚生效,需要将子方法的事务控制交给调用的方法来处理:

  方案1:子方法中不用 try-catch 处理运行异常

  方案2:子方法的catch里面将运行异常抛出【throw new RuntimeException();】
默认情况下,Spring会对unchecked异常进行事务回滚,也就是默认对 RuntimeException() 异常或是其子类进行事务回滚。
如果是checked异常则不回滚,例如空指针异常、算数异常等会被回滚;文件读写、网络问题Spring就没法回滚。

  若想对所有异常(包括自定义异常)都起作用,注解上面需配置异常类型:@Transactional(rollbackFor = Exception.class)

  数据库要支持事务,如果是mysql,要使用innodb引擎,myisam不支持事务
  事务@Transactional由spring控制时,它会在抛出异常的时候进行回滚。如果自己使用try-catch捕获处理了,是不生效的。如果想事务生效可以进行手动回滚或者在catch里面将异常抛出【throw new RuntimeException();】

方案一:手动抛出运行时异常(缺陷是不能在catch代码块自定义返回值)

  try{
      ....  
  }catch(Exception e){
      logger.error("",e);
      throw new RuntimeException(e);
  }

方案二:手动进行回滚【 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 】

  try{
      ...
  }catch(Exception e){
      log.error("fail",e);
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      return false;
  }
  • @Transactional可以放在Controller下面直接起作用,并非必须要放到@Component下面或者@Service下面
  • @Transactional引入包问题,它有两个包:
import javax.transaction.Transactional; 
// 和
import org.springframework.transaction.annotation.Transactional;         // 推荐

  这两个都可以用,对比了一下他们两个的方法和属性,发现后面的比前面的强大。建议使用后面的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"No transaction aspect-managed TransactionStatus in scope" 是Spring框架中的一条异常信息,它表示在当前的代码执行环境中,没有事务的上下文或没有事务可管理的TransactionStatus。 在Spring框架中,事务管理是通过AOP(面向切面编程)实现的。当使用@Transactional注解或编程方式配置事务Spring会在运行通过AOP拦截器来管理事务的开始、提交、回滚等操作。事务的上下文信息会被存储在TransactionStatus对象中。 当出现异常信息"No transaction aspect-managed TransactionStatus in scope",可能有以下几种情况: 1. 代码执行的上下文环境没有被Spring的事务管理器拦截或配置。 2. 代码执行的上下文环境中没有启用事务管理。 3. 代码执行的上下文环境中存在错误的事务配置,导致无法创建或获取TransactionStatus对象。 要解决这个异常,可以尝试以下几个步骤: 1. 确保在代码执行的上下文环境中正确配置了Spring的事务管理器。 2. 确保使用了@Transactional注解或编程方式正确标记需要进行事务管理的方法。 3. 检查是否存在事务配置错误,例如错误的事务传播行为或事务超设置等。 4. 确保代码执行的上下文环境中启用了Spring的AOP功能,以便进行事务拦截和管理。 如果以上步骤都没有解决该异常,可以进一步检查日志或调试代码,查找是否存在其他与事务相关的问题,例如数据库连接或事务资源的配置问题等。 需要注意的是,该异常信息可能还会包含更多的上下文信息或堆栈跟踪,可以通过查看详细的异常信息来获取更多的线索和调试信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值