spring事务失效二:业务代码捕获异常

当在Spring事务中,业务代码内部通过try-catch捕获异常时,事务不会回滚。这是因为Spring事务拦截器在处理时依赖于异常来决定是否回滚。若业务代码已捕获异常,拦截器无法捕获,导致事务意外提交。为确保事务正常回滚,应避免在加了事务注解的方法内直接捕获异常,而是记录并重新抛出异常,使事务拦截器能执行回滚操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于我们在使用事务的时候,如果我们自己的业务代码中,通过try catch去捕获了异常,那此时原本应该回滚的事务是无法进行回滚的,这个spring事务底层的处理逻辑有关系

应用

代码就不贴了,给各截图,偷个懒
在这里插入图片描述
如果这个代码去执行的时候,是没有问题的,事务会进行回滚,但是假如我们其中的一个或者两个try catch都打开之后,就会出现,原本应该回滚的事务,却不回滚了,这是在事务拦截器执行的时候,会对业务代码进行异常捕获,假如我们自己捕获了异常,事务拦截器就无法拦截到异常

为什么不回滚

为什么不回滚,是和spring事务底层的代码有关系,至于spring事务是如何生成代理对象的,如何被拦截的,就不说了,在前面的笔记中有说过,我们来看,spring事务拦截到之后,所执行的代码

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction


protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
    final InvocationCallback invocation) throws Throwable {

  // If the transaction attribute is null, the method is non-transactional.
  TransactionAttributeSource tas = getTransactionAttributeSource();
  final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
  final TransactionManager tm = determineTransactionManager(txAttr);


  PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
  final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

  if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
    // 1.根据当前是否存在事务,和不同的传播机制,去判断是要挂起事务,还是生成新的事务等
    TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

    Object retVal;
    try {
      // 2.这是去执行目标方法
      retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
      // 3.在目标方法抛出异常时,判断是否需要进行回滚
      completeTransactionAfterThrowing(txInfo, ex);
      throw ex;
    }
    finally {
      // 4.清理事务信息,恢复挂起的事务
      cleanupTransactionInfo(txInfo);
    }

    if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
      // Set rollback-only in case of Vavr failure matching our rollback rules...
      TransactionStatus status = txInfo.getTransactionStatus();
      if (status != null && txAttr != null) {
        retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
      }
    }

    commitTransactionAfterReturning(txInfo);
    return retVal;
  }
}

这是目标方法被拦截之后,执行的部分代码,也是这个问题的核心,我们可以看到,对于异常回滚的处理,是在try catch里面去处理的,也就是说,如果我们自己在业务代码中,去捕获了异常,那也意味着,在这里是无法执行到catch里面的逻辑,所以,会进行事务得提交,那这样肯定是有问题的,所以,在实际业务代码中,一定要注意,如果加了事务注解,那一定不要在代码中取捕获异常,如果说想要把异常处理的更为通用或者规范,那可以在捕获到异常之后,对异常记录或者处理之后,再抛出一个异常,这样,才能被事务的拦截器捕获到,然后进行回滚的操作,要不然,事务就失去了其意义

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值