spring如何判断当前事务是否应该回滚

本文探讨了Spring中如何判断事务是否应该回滚。在遇到异常时,实际的判断逻辑并不只是简单比较异常类型。通过分析TransactionInterceptor的源码,特别是rollbackOn方法,我们发现Spring会递归检查异常及其父类,如果异常是RuntimeException或Error的子类,事务将被回滚。这与预期的仅根据特定异常类型决定回滚的情况不同。

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

spring如何判断当前事务是否应该回滚

在没有看到源码的我理所应当的认为是判断异常类型是否相同这么简单。但是当我做了下面一个测试的时候发现和我想的完全不一样。

    @Transactional(rollbackFor = BizException.class)
    public void saveUser(User user){

        this.userService.SaveUser(user);
        int i = 1/0;
    }

前面的代码1/0会抛出一个ArithmeticException是RuntimeException的子类,BizException是我们自定义的异常也是runtimeException的子类。结果我发现竟然被回滚了。。。

所以再来看下源码。
@Transactonal对应的advice是TransactionInterceptor,当我们调用方法的时候执行的是invokeWithinTransaction方法

try {
                result = invocation.proceedWithInvocation();
            } catch (Throwable var17) {
                this.completeTransactionAfterThrowing(txInfo, var17);
                throw var17;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }

当发生异常的时候会调用completeTransactionAfterThrowing方法进行事务回滚的异常判断。

      protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }

            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var6) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    var6.initApplicationException(ex);
                    throw var6;
                } catch (Error | RuntimeException var7) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    throw var7;
                }
            } else {
                try {
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var4) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    var4.initApplicationException(ex);
                    throw var4;
                } catch (Error | RuntimeException var5) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    throw var5;
                }
            }
        }

    }

上面的逻辑代码是比较清晰的,判断当前异常类型我们回滚限定的类型,逻辑在txInfo.transactionAttribute.rollbackOn(ex))方法

	public boolean rollbackOn(Throwable ex) {
		RollbackRuleAttribute winner = null;
		int deepest = Integer.MAX_VALUE;
    
		if (this.rollbackRules != null) {
        //循环取出rule 就是我们的rollbackFor的Class<? extends Throwable>[]
			for (RollbackRuleAttribute rule : this.rollbackRules) {
            //这里为了取出层级,什么意思呢?如果当前抛出的异常是rollbackFor中的多个异常类的子类,
            //取出当前最近的那个进行rollback,如果没有匹配的上的那么就是-1 
				int depth = rule.getDepth(ex);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					winner = rule;
				}
			}
		}

		if (logger.isTraceEnabled()) {
			logger.trace("Winning rollback rule is: " + winner);
		}

		//如果没有异常匹配的上的话就会调用父类的默认的rollbackon规则。
        //父类的规则判断是继承与runtimeException或者是继承与Error。。。
		if (winner == null) {
			logger.trace("No relevant rollback rule found: applying default rules");
			return super.rollbackOn(ex);
		}
        //如果最终拿到的是不需要回滚的rule的话也是不回滚的
		return !(winner instanceof NoRollbackRuleAttribute);
	}
	父类的判断是否回滚的判断

public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}

getDepth的代码如下:很简单的一个递归,不做过多的解释了。

public int getDepth(Throwable ex) {
		return getDepth(ex.getClass(), 0);
	}


	private int getDepth(Class<?> exceptionClass, int depth) {
		if (exceptionClass.getName().contains(this.exceptionName)) {
			// Found it!
			return depth;
		}
		// If we've gone as far as we can go and haven't found it...
		if (exceptionClass == Throwable.class) {
			return -1;
		}
		return getDepth(exceptionClass.getSuperclass(), depth + 1);
	}

上面的代码说实话对我来说有点颠覆。
1.首先异常的判断是会递归判断父级的。这个以前没有仔细研究过
2.然后如果最终没有匹配的上exception的话会最终判断当前抛出的异常是否是runtimeException的子类或者是Error的子类,然后最终判断是否回滚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值