SpringBoot中事务执行原理分析(五)

72 篇文章 18 订阅
52 篇文章 3 订阅

关联博文:
SpringBoot中事务执行原理分析(一)
SpringBoot中事务执行原理分析(二)
SpringBoot中事务执行原理分析(三)
SpringBoot中事务执行原理分析(四)
SpringBoot中事务执行原理分析(五)
SpringBoot中事务执行原理分析(六)
SpringBoot中事务执行原理分析补充篇
你认真研究过Spring中的@EnableTransactionManagement注解吗?

接上文SpringBoot中事务执行原理分析(四)我们分析过方法正常执行完事务提交后,本文我们继续分析目标方法抛出异常后事务的回滚流程,即 completeTransactionAfterThrowing(txInfo, ex)

TransactionAspectSupport的completeTransactionAfterThrowing方法如下。

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);
		}
		//判断当前异常类型是否需要回滚
		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;
			}
		}
	}
}

这里首先对事务信息对象和事务状态对象做了判断,如果其中有一个为 null 则直接跳过不做处理。然后对异常类型做了判断,判断当前异常类型时触发 rollback 还是 commit动作。关于commit动作我们前面已经分析过了,本文我们分析rollback动作。

AbstractPlatformTransactionManager的rollback方法

@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
	processRollback(defStatus, false);
}

可以看到其rollback方法只是对status做了是否已经完成的状态校验,然后交给了processRollback方法。

AbstractPlatformTransactionManager的processRollback方法。

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
	try {
	//初值false 
		boolean unexpectedRollback = unexpected;

		try {
		//遍历触发TransactionSynchronization的beforeCompletion方法
			triggerBeforeCompletion(status);

//如果有savepoint则首先回滚到savepoint位置然后释放savepoint
			if (status.hasSavepoint()) {
				if (status.isDebug()) {
					logger.debug("Rolling back transaction to savepoint");
				}
				status.rollbackToHeldSavepoint();
			}
//如果事务是新事务,则触发rollBack动作
			else if (status.isNewTransaction()) {
				if (status.isDebug()) {
					logger.debug("Initiating transaction rollback");
				}
				doRollback(status);
			}
			//如果当前事务是一个已经存在的事务
			else {
				// Participating in larger transaction
				if (status.hasTransaction()) {
					if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
						if (status.isDebug()) {
							logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
						}
						//修改rollbackOnly状态为true
						doSetRollbackOnly(status);
					}
					else {
						if (status.isDebug()) {
							logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
						}
					}
				}
				else {
					logger.debug("Should roll back transaction but cannot - no transaction available");
				}
				// Unexpected rollback only matters here if we're asked to fail early
				if (!isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = false;
				}
			}
		}
		catch (RuntimeException | Error ex) {
//遍历触发TransactionSynchronization 的afterCompletion  状态是STATUS_UNKNOWN
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw ex;
		}
//遍历触发TransactionSynchronization 的afterCompletion  状态是STATUS_ROLLED_BACK
		triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

		// Raise UnexpectedRollbackException if we had a global rollback-only marker
		if (unexpectedRollback) {
			throw new UnexpectedRollbackException(
					"Transaction rolled back because it has been marked as rollback-only");
		}
	}
	finally {
	// 完成后清理事务信息
		cleanupAfterCompletion(status);
	}
}

方法流程梳理如下:

  • 遍历触发TransactionSynchronization的beforeCompletion方法
  • 如果有savepoint则首先回滚到savepoint位置然后释放savepoint
  • 如果事务是新事务,则触发rollBack动作
  • 如果当前事务是一个已经存在的事务,则可能设置事务状态rollbackOnly为true
  • 遍历触发TransactionSynchronization 的afterCompletion
  • 完成后清理事务信息-cleanupAfterCompletion

可以看到,这里同前文提交分析流程类型,同样触发了TransactionSynchronization的钩子函数,对事务进行了判断处理最后清理事务资源。

cleanupAfterCompletion同前文一致,TransactionSynchronization我们另起篇章分析。我们接下来看下核心方法doRollback(status);


DataSourceTransactionManager的doRollback方法

@Override
protected void doRollback(DefaultTransactionStatus status) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
	Connection con = txObject.getConnectionHolder().getConnection();
	if (status.isDebug()) {
		logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
	}
	try {
		con.rollback();
	}
	catch (SQLException ex) {
		throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
	}
}

方法如上所示其从事务对象里面获取到连接对象,然后触发数据库连接对象的rollback方法。

本文这里获取到的数据库连接对象是:HikariProxyConnection@2062395789 wrapping com.mysql.cj.jdbc.ConnectionImpl@12ee6186。可以看到其内有委派对象delegate=ConnectionImpl
在这里插入图片描述

ProxyConnection 的rollback方法

@Override
public void rollback() throws SQLException
{
   delegate.rollback();
   isCommitStateDirty = false;
   lastAccess = currentTime();
}

再往下就交给了MySQL驱动来实现这个功能,如下所示,其最终触发了this.session.execSQL(null, "rollback", -1, null, false, this.nullStatementResultSetFactory, null, false);
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值