都2021年了,不会还不知道Spring事务的回滚处理和提交的原理吧?

本文详细探讨了Spring事务的回滚处理和提交原理。从回滚条件出发,解释了默认情况下如何处理Exception以及如何通过注解改变回滚行为。接着,通过源码分析,展示了Spring如何在出现特定异常时回滚事务,以及如何在没有异常时提交事务。重点讲解了hasSavepoint、isNewTransaction、hasTransaction等方法在回滚和提交过程中的作用,最后简要介绍了事务完成后的清理工作。
摘要由CSDN通过智能技术生成

这篇文章讲事务剩下的回滚和提交。

事务的回滚处理

之前已经完成了目标方法运行前的事务准备工作。而这些准备工作的最大目的无非就是对于程序没有按照我们期待的那样进行,也就是出现特定的错误;那么当出现错误的时候Spring是怎么对数据进行恢复的呢?我们先来看一下 TransactionAspectSupport 类里的 invokeWithinTransaction 函数的 completeTransactionAfterThrowing 方法(其它的已经在上一篇文章讲解过,这里不再赘述):

  • 看源码( TransactionAspectSupport.java )
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    // 当抛出异常时,先判断当前是否存在事务,这是基础依据
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                                    "] after exception: " + ex);
        }
        // 这里判断是否回滚默认的 依据是抛出的异常是RunTimeException 或者是 Erro 类型r
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }
            catch (TransactionSystemException ex2) {
                logger.error("Application exception overridden by rollback exception", ex);
                ex2.initApplicationException(ex);
                throw ex2;
            }
            catch (RuntimeException | Error ex2) {
                logger.error("Application exception overridden by rollback exception", ex);
                throw ex2;
            }
        } else {
            // We don't roll back on this exception.
            // Will still roll back if TransactionStatus.isRollbackOnly() is true.
            // 如果不满足回滚条件,即使抛出异常也正常提交    
            try {
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            }
            catch (TransactionSystemException ex2) {
                logger.error("Application exception overridden by commit exception", ex);
                ex2.initApplicationException(ex);
                throw ex2;
            }
            catch (RuntimeException | Error ex2) {
                logger.error("Application exception overridden by commit exception", ex);
                throw ex2;
            }
        }
    }
}
  • 源码分析

在对目标方法的执行过程中,一旦出现 Throwable 就会被引导至此方法进行处理,但是不意味着所有的 Throwable 都会被回滚处理;比如我么最常用的Exception,默认是不会被处理的,默认情况下,即使出现异常,数据也会被正常提交,而这个关键的地方就在于 txInfo.transactionAttribute.rollbackOn(ex) 这个函数:

回滚条件

  • 看源码( DefaultTransactionAttribute.java )
@Override
public Boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}
  • 源码分析

从上述代码中可以看到,默认情况下:Spring只会对 RuntimeException 和 Error 两种类型的情况进行处理;但是我们可以利用注解方式来改变。例如:

@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)

回滚处理

当然,一旦符合回滚条件,那么Spring就会将程序引导至回滚处理函数中。接下来我们看一下回滚函数,也就是 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); 代码的rollback方法:

  • 看源码( AbstractPlatformTransactionManager.java )
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
    if (status.isCompleted()) {
        throw new IllegalTransactionStateException(
                            "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    processRollback(defStatus, false);
}

看一下这个方法里面的 processRollback 函数:

  • 看源码( AbstractPlatformTransactionManager.java )
private void processRollback(DefaultTransactionStatus status, Boolean unexpected) {
    try {
        Boolean unexpectedRollback = unexpected;
        try {
            triggerBeforeCompletion(status);
            // 如果status 有 savePoint , 说明此事务 是 PROPAGATION_NESTED 且为子事务,只能回滚到savePoint
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    logger.debug("Rolling back transaction to savepoint");
                }
                // 回滚到保存点
                status.rollbackToHeldSavepoint();
            }
            // 如果此时的status显示的是新的事务,才进行回滚 else if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    logger.debug("Initiating transaction rollback");
                }
           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值