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

简介: SpringBoot中事务执行原理分析(四)

关联博文:

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

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

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


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

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

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

SpringBoot中事务执行原理分析补充篇

你认真研究过Spring中的@EnableTransactionManagement注解吗?


接上文SpringBoot中事务执行原理分析(三)我们分析过事务信息对象的获取后,本文我们继续分析目标方法执行后事务的提交流程,即 commitTransactionAfterReturning(txInfo);。


如下所示TransactionAspectSupport的事务提交动作交给了事务管理器来处理。

// org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
//如果事务信息对象或者事务状态对象为null,则do nothing
  if (txInfo != null && txInfo.getTransactionStatus() != null) {
    if (logger.isTraceEnabled()) {
      logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
    }
    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  }
}


事务提交动作交给了AbstractPlatformTransactionManager的commit方法。

@Override
public final void commit(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;
  // 判断rollbackOnly,本文这里是false
  if (defStatus.isLocalRollbackOnly()) {
    if (defStatus.isDebug()) {
      logger.debug("Transactional code has requested rollback");
    }
    //触发rollBack
    processRollback(defStatus, false);
    return;
  }
//shouldCommitOnGlobalRollbackOnly默认为false ,后者则判断ConnectionHolder中的rollbackOnly属性
  if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
    if (defStatus.isDebug()) {
      logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
    }
    processRollback(defStatus, true);
    return;
  }
// 其实核心是这里,前面只是做了回滚机制校验
  processCommit(defStatus);
}



方法如上所示,首先校验事务完成状态,然后对回滚机制做了校验,最后才是核心方法processCommit(defStatus);

【1】 核心方法processCommit

AbstractPlatformTransactionManager的processCommit方法。

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
  try {
    boolean beforeCompletionInvoked = false;
    try {
      boolean unexpectedRollback = false;
      // 默认是空方法
      prepareForCommit(status);
      //遍历触发TransactionSynchronization的beforeCommit方法
      triggerBeforeCommit(status);
      //遍历触发TransactionSynchronization的beforeCompletion方法
      triggerBeforeCompletion(status);
      //修改标志为为true
      beforeCompletionInvoked = true;
      //如果有Savepoint,释放持有的savepoint
      if (status.hasSavepoint()) {
        if (status.isDebug()) {
          logger.debug("Releasing transaction savepoint");
        }
        unexpectedRollback = status.isGlobalRollbackOnly();
        status.releaseHeldSavepoint();
      }
      //如果是一个新事务
      else if (status.isNewTransaction()) {
        if (status.isDebug()) {
          logger.debug("Initiating transaction commit");
        }
        unexpectedRollback = status.isGlobalRollbackOnly();
        //执行实际的提交,触发Connection的commit,这个执行完毕数据将会进入数据库
        doCommit(status);
      }
      else if (isFailEarlyOnGlobalRollbackOnly()) {
      // 如果failEarlyOnGlobalRollbackOnly为true,默认为false
        unexpectedRollback = status.isGlobalRollbackOnly();
      }
      // Throw UnexpectedRollbackException if we have a global rollback-only
      // marker but still didn't get a corresponding exception from commit.
      if (unexpectedRollback) {
        throw new UnexpectedRollbackException(
            "Transaction silently rolled back because it has been marked as rollback-only");
      }
    }
    catch (UnexpectedRollbackException ex) {
      // can only be caused by doCommit
      //遍历触发TransactionSynchronization 的afterCompletion  状态是STATUS_ROLLED_BACK
      triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
      throw ex;
    }
    catch (TransactionException ex) {
      // can only be caused by doCommit
      //如果提交失败导致的回滚,则触发回滚
      if (isRollbackOnCommitFailure()) {
        doRollbackOnCommitException(status, ex);
      }
      else {
      //遍历触发TransactionSynchronization 的afterCompletion 状态是STATUS_UNKNOWN
        triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
      }
      throw ex;
    }
    catch (RuntimeException | Error ex) {
      if (!beforeCompletionInvoked) {
        triggerBeforeCompletion(status);
      }
      //如果提交失败导致的回滚,则触发回滚
      doRollbackOnCommitException(status, ex);
      throw ex;
    }
    // Trigger afterCommit callbacks, with an exception thrown there
    // propagated to callers but the transaction still considered as committed.
    try {
    //遍历触发TransactionSynchronization的afterCommit方法
      triggerAfterCommit(status);
    }
    finally {
    //遍历触发TransactionSynchronization的afterCompletion方法,状态是STATUS_COMMITTED
      triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
    }
  }
  finally {
  //完成后清理事务信息
    cleanupAfterCompletion(status);
  }
}



方法简单来讲分为四个部分:


triggerXXXX触发TransactionSynchronization事务同步器的各种钩子函数,如果我们想做一些处理就可以实现这个接口或者继承自TransactionSynchronizationAdapter,像SqlSessionSynchronization一样。

savepoint的处理,如果持有savepoint则释放savepoint;

doCommit(status);执行实际的提交,这里会交给Connection去处理,执行完数据就进入了数据库;

cleanupAfterCompletion(status),处理完毕清理一些信息。

事务同步各种钩子我们另起篇章分析,我们这里看一下事务的提交和最后的清理。

【2】 事务真正提交doCommit

事务提交如下所示,其核心是将动作交给了数据库连接来处理commit

//org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit
@Override
protected void doCommit(DefaultTransactionStatus status) {
//获取到持有的事务对象
  DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  //从事务对象获取持有的连接信息
  Connection con = txObject.getConnectionHolder().getConnection();
  if (status.isDebug()) {
    logger.debug("Committing JDBC transaction on Connection [" + con + "]");
  }
  try {
  //提交动作交给连接
    con.commit();
  }
  catch (SQLException ex) {
    throw new TransactionSystemException("Could not commit JDBC transaction", ex);
  }
}



这里最终会下发下面这个命令执行事务的提交:

this.session.execSQL(null, "commit", -1, null, false, this.nullStatementResultSetFactory, null, false);


【3】 最后的清理cleanupAfterCompletion


实现将当前事务状态信息设置为已完成,然后判断是新事务则触发事务同步管理器的clear,会清空线程本地副本资源。如果是新事务还会重置并释放连接、重置ConnectionHolder属性为默认值。最后判断是否有挂起资源,如果有则恢复。

//org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
//设置事务状态已完成
  status.setCompleted();
//如果是新事务,触发事务同步管理器的clear,会清空线程本地副本资源
  if (status.isNewSynchronization()) {
    TransactionSynchronizationManager.clear();
  }
  //如果是新事务触发doCleanupAfterCompletion
  if (status.isNewTransaction()) {
  // 重置并释放连接,重置ConnectionHolder属性为默认值
    doCleanupAfterCompletion(status.getTransaction());
  }
  //如果挂起资源不为null,则恢复挂起的资源
  if (status.getSuspendedResources() != null) {
    if (status.isDebug()) {
      logger.debug("Resuming suspended transaction after completion of inner transaction");
    }
    Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
    resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
  }
}


DataSourceTransactionManager的doCleanupAfterCompletion方法

//org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion
@Override
protected void doCleanupAfterCompletion(Object transaction) {
  DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
  // Remove the connection holder from the thread, if exposed.
  if (txObject.isNewConnectionHolder()) {
  // 如果是新的connectionHolder则从 本地线程上下文对象resources移除当前持有的ConnectionHolder
    TransactionSynchronizationManager.unbindResource(obtainDataSource());
  }
  // Reset connection. 重置连接,为释放连接做准备
  Connection con = txObject.getConnectionHolder().getConnection();
  try {
    if (txObject.isMustRestoreAutoCommit()) {
      con.setAutoCommit(true);
    }
    DataSourceUtils.resetConnectionAfterTransaction(
        con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
  }
  catch (Throwable ex) {
    logger.debug("Could not reset JDBC Connection after transaction", ex);
  }
  if (txObject.isNewConnectionHolder()) {
    if (logger.isDebugEnabled()) {
      logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
    }
    //如果newConnectionHolder 为true,则释放连接
    DataSourceUtils.releaseConnection(con, this.dataSource);
  }
//清理ConnectionHolder,也就是恢复其属性为默认值
  txObject.getConnectionHolder().clear();
}



ConnectionHolder的clear方法如下所示,其还触发了父类的clear方法。简单来讲,其就是恢复了成员的默认值。

//ConnectionHolder
@Override
public void clear() {
  super.clear();
  this.transactionActive = false;
  this.savepointsSupported = null;
  this.savepointCounter = 0;
}
//ResourceHolderSupport
public void clear() {
  this.synchronizedWithTransaction = false;
  this.rollbackOnly = false;
  this.deadline = null;
}


目录
相关文章
|
6月前
|
NoSQL Java Redis
SpringBoot原理分析 | Redis集成
SpringBoot原理分析 | Redis集成
62 0
|
6月前
|
druid Java 数据库连接
SpringBoot原理分析 | Spring Data整合:JDBC、Druid、Mybatis
SpringBoot原理分析 | Spring Data整合:JDBC、Druid、Mybatis
128 0
|
3月前
|
安全 Java API
SpringBoot + 事务钩子函数,打造高效支付系统!
【8月更文挑战第9天】在当今快速发展的数字支付时代,构建一个稳定、高效且安全的支付系统是企业数字化转型的关键一步。SpringBoot以其简洁的配置、快速的开发速度以及强大的生态支持,成为了构建支付系统的热门选择。而结合事务钩子函数(Transaction Hooks),则能进一步确保支付流程的完整性、一致性和可维护性。以下,我将分享如何利用SpringBoot与事务钩子函数来打造高效支付系统的技术实践。
97 15
SpringBoot + 事务钩子函数,打造高效支付系统!
|
5月前
|
Java
SpringBoot起步依赖原理分析
SpringBoot起步依赖原理分析
|
6月前
|
存储 缓存 Java
SpringBoot 整合多数据源的事务问题
多数据源实现、切面的优先级问题(Order注解)、事务的传播特性(Propagation类)
|
5月前
|
Java 关系型数据库 MySQL
SpringBoot系列教程之事务传递属性
SpringBoot系列教程之事务传递属性
|
6月前
|
监控 Java 测试技术
Spring Boot与事务钩子函数:概念与实战
【4月更文挑战第29天】在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
169 1
|
11月前
|
XML 设计模式 Java
SpringBoot中事务执行原理分析(一)
SpringBoot中事务执行原理分析(一)
99 1
|
6月前
|
安全 Java 数据库
SpringBoot原理分析 | 安全框架:Shiro
SpringBoot原理分析 | 安全框架:Shiro
54 0
|
6月前
|
Java
SpringBoot原理分析 | 任务:异步、邮件、定时
SpringBoot原理分析 | 任务:异步、邮件、定时
79 0