Spring事务(二)——事务的提交

             上一章(文章地址:Spring事务(一)——切面的创建_奔跑的蜗牛_Kieasar的博客-CSDN博客_spring事务切面),匹配到了有@Transactional注解的方法,创建好了切面,然后在AbstractPlatformTransactionManager.getTransaction()方法中创建了事务对象,我们先回顾一下getTransaction()方法:

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

		// 得到一个DataSourcetranctionObject类(就是事务对象)****
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

		// 判断之前是否已存在事务对象(第一次进来为空)
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			// 如果不是第一次进来, 则走这里,表示之前已开启事务,则为现有事务创建TransactionStatus。
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		// 检查事务设置的超时时间
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// 下面处理事务的传播机制
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		// 若事务属性式为PROPAGATION_MANDATORY,表示必须运行在事务中,没有就抛出异常
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		/**
		 * 如果存在事务,以下三种传播机制都会进入相同的处理逻辑
		 * PROPAGATION_REQUIRED:存在事务就加入到当前的事务,没有就新开一个
		 * PROPAGATION_REQUIRES_NEW:新开一个事务,若当前存在事务就挂起当前事务
		 * PROPAGATION_NESTED: 表示如果当前正有一个事务在运行中,则该方法应该运行在一个嵌套的事务中,
		 * 被嵌套的事务可以独立于封装事务进行提交或者回滚(保存点),如果封装事务不存在,行为就像PROPAGATION_REQUIRES_NEW
		 */
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			/**
			 * 挂起当前事务,SuspendedResources表示当前线程被挂起的资源持有对象(数据库连接、TransactionSynchronization)
			 * 逻辑走到这里,经过了上面的isExistingTransaction(transaction)可以断定当前不存在事务,所有这里挂起当前事务传递一个null进去
			 */
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				// 开启新事务,事务中就会有数据库连接了,并且isTransactionActive为true
				// 新创建一个事务状态TransactionStatus对象,该对象保存了很多信息,包括被挂起的资源(重要程度:5)
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 创建一个空的事务
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

        接下来进行校验,判断之前是否已存在事务,进入isExistingTransaction():

        所属类:org.springframework.jdbc.datasource.DataSourceTransactionManager

	protected boolean isExistingTransaction(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		// 若第一次进来开始事务,txObject.hasConnectionHolder()返回null,表示不存在事务
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}

        第一次执行肯定为空,如果之前已开启事务,就会为现有事务创建TransactionStatus,进入handleExistingTransaction():

        所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

		// 判断当前的事务行为是不是PROPAGATION_NEVER,表示不支持事务,如果当前存在事务则抛出异常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}

		// 判断当前的事务属性不支持事务,PROPAGATION_NOT_SUPPORTED,需要先挂起已经存在的事务
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction");
			}
			// 把当前事务挂起,其中会把数据库连接对象从ThreadLocal中移除
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 创建一个新的非事务状态(保存了上一个存在事务状态的属性)
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		// 判断当前的事务属性状态是PROPAGATION_REQUIRES_NEW表示需要新开启一个事务状态
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
			// 挂起已经存在的事务
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
				// 创建一个新的事务(包含挂起的事务的属性)
				return startTransaction(definition, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}

			// 嵌套事务的处理
			if (useSavepointForNestedTransaction()) {
				// Create savepoint within existing Spring-managed transaction,
				// through the SavepointManager API implemented by TransactionStatus.
				// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
				// 开启一个新的事务
				DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				// 为事务设置一个回退点
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				return startTransaction(definition, transaction, debugEnabled, null);
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}
		if (isValidateExistingTransaction()) {
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
					Constants isoConstants = DefaultTransactionDefinition.constants;
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] specifies isolation level which is incompatible with existing transaction: " +
							(currentIsolationLevel != null ?
									isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
									"(unknown)"));
				}
			}
			if (!definition.isReadOnly()) {
				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] is not marked as read-only but existing transaction is");
				}
			}
		}
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		// 如果第二次进来还是PROPAGATION_REQUIRED,走这里,newTransaction属性为false
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

        这个方法会对不同的传播属性分别处理,如果是PROPAGATION_REQUIRED属性,会执行最后一行代码,需要注意newTransaction属性,该属性决定后面方法事务的是否提交,会创建DefaultTransactionStatus的事务状态对象,记录事务的一些属性。

        所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	protected final DefaultTransactionStatus prepareTransactionStatus(
			TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
			boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {

		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
		prepareSynchronization(status, definition);
		return status;
	}

        另外,suspendedResources属性会涉及到事务的挂起,挂起的事务会封装到这里,后面详细说。

         回到getTransaction(txAttr)方法,如果隔离级别是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED,这三种传播属性会按相同逻辑去处理,就会进入suspend()挂起事务的方法:

	protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
		/**
		 * 判断当前的线程变量中是否有激活的事务,有的话需要清空线程变量,
		 * synchronizations是一个ThreadLocal<Set<TransactionSynchronization>>,
		 * 可以给任何地方通过TransactionSynchronizationManager给当前线程添加TransactionSynchronization
		 */
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			// 调用TransactionSynchronization的suspend()方法,并清空和返回当前线程中所有的TransactionSynchronization对象
			List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
			try {
                // SuspendedResources表示当前线程被挂起的资源持有对象(数据库连接、TransactionSynchronization)
				Object suspendedResources = null;
				if (transaction != null) {
					suspendedResources = doSuspend(transaction);
				}
				// 获取并清空当前线程中关于事务TransactionSynchronizationManager的配置信息:
				String name = TransactionSynchronizationManager.getCurrentTransactionName();
				TransactionSynchronizationManager.setCurrentTransactionName(null);
				boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
				TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
				Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
				boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
				TransactionSynchronizationManager.setActualTransactionActive(false);

				// 将当前线程中的数据库连接对象、TransactionSynchronization对象、TransactionSynchronizationManager对象封装成一个对象返回
				// 表示被挂起的资源对象持有了当前线程中的事务对象、TransactionSynchronization对象
				return new SuspendedResourcesHolder(
						suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
			}
			catch (RuntimeException | Error ex) {
				// doSuspend failed - original transaction is still active...
				doResumeSynchronization(suspendedSynchronizations);
				throw ex;
			}
		}
		else if (transaction != null) {
			// Transaction active but no synchronization active.
			Object suspendedResources = doSuspend(transaction);
			return new SuspendedResourcesHolder(suspendedResources);
		}
		else {
			// Neither transaction nor synchronization active.
			return null;
		}
	}

         回到getTransaction(txAttr)方法,进入startTransaction(),该方法是开启事务的重要方法。

        所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		// 是否开启一个新的TransactionSynchronization
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

		// 创建一个新事务状态,包括:是否是新事务(newTransaction为true)、事务定义、连接对象、是否是新的TransactionSynchronization
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

		// 开启新事务
		doBegin(transaction, definition);

		// 根据需要初始化事务同步,把新创建事务的一些信息(事务名、隔离级别、readOnly)设置到TransactionSynchronizationManager类中,该类有多个ThreadLocal
		prepareSynchronization(status, definition);
		return status;
	}

        进入doBegin()方法取开启事务:

        所属类:org.springframework.jdbc.datasource.DataSourceTransactionManager

	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			// 检查事务中是否有连接对象(DataSource)
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// 没有的话通过数据源管理器拿DataSource对象,再从DataSource中获取连接对象
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				// 把连接对象包装成一个ConnectionHolder,并设置到事务对象(txObject)中
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}
			// 设置有事务的标识
			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			// 根据@Transactional注解配置的隔离级别,设置数据库连接的是否只读与隔离级别
			// 代码中仅设置了隔离级别,后面未做任何处理
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			// 设置该连接的上一个隔离级别
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			txObject.setReadOnly(definition.isReadOnly());

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				// 关闭自动提交,提交由Spring控制
				con.setAutoCommit(false);
			}
			// 判断事务为只读事务
			prepareTransactionalConnection(con, definition);
			// 设置事务状态(是否为活跃的)为true
			txObject.getConnectionHolder().setTransactionActive(true);

			// 设置事务(数据库连接)超时时间
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			// 把连接对象和当前线程进行绑定,把数据源和连接的绑定关系设置到ThreadLocal<Map<数据源,连接对象>>,为threadId和Map的映射关系
			// 后面就可以通过threadId拿到Map,进而通过相同的数据源对象拿到数据库连接
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				// 释放数据库连接
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}

        doBegin()做了以下事情:

  • 从DataSource中获取数据库连接,并包装成ConnectionHolder,设置到事务对象txObject中;
  • 设置事务的readOnly和隔离级别等属性;
  • 关闭自动提交(事务开启的前提);
  • 把数据源和数据库连接的绑定关系设置到ThreadLocal中,线程id为key,绑定关系的Map为value。

        对于事务的隔离级别,上面的代码虽然进行了设置,但在后面的逻辑中,Spring未做任何处理,以MySQL为准。

        开启事务后,改变事务状态,进入prepareSynchronization()方法:

        所属类:org.springframework.jdbc.datasource.DataSourceTransactionManager

	/**
	 * 初始化事务状态,TransactionSynchronizationManager就是工具类,可以拿到隔离级别、是否只读;DefaultTransactionStatus是Spring内部的
	 */
	protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
		if (status.isNewSynchronization()) {
			// 绑定事务激活
			TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
			// 当前事务的隔离级别
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
					definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
							definition.getIsolationLevel() : null);
			// 是否为只读事务
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
			// 事务的名称
			TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
			TransactionSynchronizationManager.initSynchronization();
		}
	}

        总之,getTransaction()方法就是开启事务,建立绑定关系,返回事务状态;最终在TransactionAspectSupport类的createTransactionIfNecessary()中把事务状态和事务属性等信息封装成一个TransactionInfo对象返回。

        回到TransactionAspectSupport类的invokeWithinTransaction()方法,我们先看提交事务的方法commitTransactionAfterReturning(): 

	protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
            // 进入commit()方法看具体的提交逻辑
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}

         所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	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");
		}

		// 可以通过TransactionAspectSupport。currentTransactionStatus().setRollbackOnly()设置
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		// 设置事务强制回滚
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			// 回滚逻辑
			processRollback(defStatus, false);
			return;
		}

		// 判断此事务在此之前是否设置了需要回滚,跟globalRollbackOnParticipationFailure有关
		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()方法:

        事务状态DefaultTransactionStatus类中newTransaction属性很重要,用来控制事务提交

	private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				// 调用beforeCommit()方法,事务提交之前做业务处理
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;

				// 如果有回滚点
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					status.releaseHeldSavepoint();
				}
				// 如果是新事务(前面提交的newTransaction属性),则提交
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					// 事务提交
					doCommit(status);
				}
				else if (isFailEarlyOnGlobalRollbackOnly()) {
					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
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
				throw ex;
			}
			catch (TransactionException ex) {
				// can only be caused by doCommit
				if (isRollbackOnCommitFailure()) {
					doRollbackOnCommitException(status, ex);
				}
				else {
					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 {
				// 触发afterCommit()方法,事务提交之后做业务处理
				triggerAfterCommit(status);
			}
			finally {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
			}

		}
		finally {
			// 处理挂起事务,恢复绑定关系
			cleanupAfterCompletion(status);
		}
	}

        事务提交doCommit(status)最终执行JDK的事务提交方法:

        所属类:org.springframework.jdbc.datasource.DataSourceTransactionManager

	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 {
			// 调用JDK的事务提交方法
			con.commit();
		}
		catch (SQLException ex) {
			throw new TransactionSystemException("Could not commit JDBC transaction", ex);
		}
	}

        这就是整个事务切面的执行过程,事务提交后释放连接资源,看AbstractPlatformTransactionManager.processCommit()方法的最后:

    finally {
			// 处理挂起事务,恢复绑定关系
			cleanupAfterCompletion(status);
		}

         在这里会释放连接

        所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	private void cleanupAfterCompletion(DefaultTransactionStatus status) {
		status.setCompleted();
		if (status.isNewSynchronization()) {
			TransactionSynchronizationManager.clear();
		}
		if (status.isNewTransaction()) {
			// 释放数据库连接
			doCleanupAfterCompletion(status.getTransaction());
		}

		// 恢复被挂起的连接对象到当前线程中
		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());
		}
	}

        进入doCleanupAfterCompletion()方法:

        所属类:org.springframework.jdbc.datasource.DataSourceTransactionManager

	protected void doCleanupAfterCompletion(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

		// Remove the connection holder from the thread, if exposed.
		// 解除绑定,从线程中移除数据库连接
		if (txObject.isNewConnectionHolder()) {
			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");
			}
		    // 释放连接对象,并没有关闭,只是归还到数据库连接池.
			DataSourceUtils.releaseConnection(con, this.dataSource);
		}

		txObject.getConnectionHolder().clear();
	}

         在这里解除绑定,释放数据库连接。

        如果有异常则进行回滚,进入invokeWithinTransaction()方法的completeTransactionAfterThrowing():

        所属类:org.springframework.transaction.interceptor.TransactionAspectSupport

	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);
			}

			// 判断事务回滚的异常类型,如果抛出的异常和注解中配置的异常(rollbackFor属性)匹配,进行回滚
			// transactionAttribute的实现类为RuledBasedTransactionAttribute,父类为DefaultTransactionAttribute
			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;
				}
			}
		}
	}

         在这里,会把抛出的异常传进来,和注解中配置的异常(rollbackFor属性)进行比较,如果匹配,返回执行回滚逻辑。

        如果不匹配则找当前异常的父类再和注解中配置的异常进行匹配,最终看异常类型是否为RuntimeException或Error类型,如果是也会走回滚逻辑,否则,执行commit操作。 

         所属类:org.springframework.transaction.interceptor.RuleBasedTransactionAttribute

	public boolean rollbackOn(Throwable ex) {
		if (logger.isTraceEnabled()) {
			logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
		}

		RollbackRuleAttribute winner = null;
		int deepest = Integer.MAX_VALUE;

		if (this.rollbackRules != null) {
			// 遍历所有的RollbackRuleAttribute,判断现在抛出的异常ex是否匹配RollbackRuleAttribute中所指定的异常类型
			for (RollbackRuleAttribute rule : this.rollbackRules) {
				int depth = rule.getDepth(ex);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					winner = rule;
				}
			}
		}

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

		// User superclass behavior (rollback on unchecked) if no rule matches.
		if (winner == null) {
			logger.trace("No relevant rollback rule found: applying default rules");
		    // 和父类DefaultTransactionAttribute的方法去匹配.
			return super.rollbackOn(ex);
		}
		// ex所匹配的RollbackRuleAttribute,可能是NoRollbackRuleAttribute,如果匹配的是NoRollbackRuleAttribute,则表示这个异常ex不用回滚
		return !(winner instanceof NoRollbackRuleAttribute);
	}

         进入本类的getDepth() 方法:

	private int getDepth(Class<?> exceptionClass, int depth) {
		// exceptionClass为抛出的异常,this.exceptionName指@Transactional注解中配置的异常
		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);
	}

        接下来,回到completeTransactionAfterThrowing()方法看回滚逻辑:

        所属类:org.springframework.transaction.support.AbstractPlatformTransactionManager

	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);
	}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
			boolean unexpectedRollback = unexpected;

			try {
				triggerBeforeCompletion(status);
				// 是否存在回滚点,如mysql的savepoint
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
					// 回滚到上一个savepoint位置
					status.rollbackToHeldSavepoint();
				}
				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设置到ConnectionHolder中取,表示整个事务都要回滚
							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;
					}
				}
			}

        最后,通过例子来说明,比如a()调用b()的情况:

  1. 首先,代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a;
  2. 将数据库连接a的autocommit改为false;
  3. 把数据库连接a设置到ThreadLocal;
  4. 执行a()方法中的sql;
  5. 执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法):
  • 代理对象执行b()方法前,可以判断出当前线程中已存在数据库连接a,表示当前线程其实已经拥有一个Spring事务了,则进行挂起;
  • 挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入到一个挂起资源对象中;
  • 挂起完成后,再次利用事务管理器新建一个数据库连接b;
  • 将数据库连接b的autocommit改为false;
  • 把数据库连接b设置到ThreadLocal中;
  • 执行b()方法中的sql;
  • b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交;
  • 提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中。

    6.a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交,这个过程中最为核心的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

猜你喜欢

转载自blog.csdn.net/qq_40213907/article/details/121155669