spring事务传播机制源码学习笔记

这篇笔记主要记录,在spring事务源码中,传播机制的学习

传播机制枚举值

在这里插入图片描述
这是在网上扒的一张图,主要是记录事务传播机制的类型

接下来记录源码的处理逻辑

源码

事务传播机制的处理

传播机制的源码,我们从这个方法开始看起:

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

对于事务传播机制的行为,无非就是两种场景:当前存在事务,当前不存在事务,所以,spring源码中,也是根据这两种场景做了不同的处理

/**
	 * This implementation handles propagation behavior. Delegates to
	 * {@code doGetTransaction}, {@code isExistingTransaction}
	 * and {@code doBegin}.
	 * @see #doGetTransaction
	 * @see #isExistingTransaction
	 * @see #doBegin
	 *
	 * 在这个方法中,有两个比较重要的方法:分别是suspend()和doBegin()
	 * suspend()是将当前事务挂起,所谓的挂起就是事务中的属性信息暂时存到SuspendTransactionResource
	 * doBegin()
	 * 是开启一个事务,所谓的开启事务,就是获取一个数据库连接,然后将连接信息绑定到DataSourceTransactionObject上
	 */
	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    
    
		/**
		 * TODO 这里是获取到当前的事务对象,这里待学习
		 * 1、这里是new一个新的DataSourceTransactionObject对象
		 * 在后面开启事务 doBegin()方法中,会对txObject对象进行填充
		 */
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
    
    
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}

		/**
		 * 2、如果当前存在事务,就根据不同的传播机制来处理
		 * 		PROPAGATION_NOT_SUPPORTED:以非事务方法运行,如果存在事务,就把当前事务挂起
		 * 		PROPAGATION_REQUIRES_NEW:新建事务,如果存在事务,就把当前事务挂起
		 * 		PROPAGATION_NESTED:如果当前事务存在,就嵌套事务运行,如果事务不存在,就创建新的事务
		 * 		PROPAGATION_NEVER:以非事务运行,如果当前存在事务,就抛出异常
		 *
		 *
		 * 如果没有进入这个if判断,就表示当前不存在事务
		 * 		PROPAGATION_MANDATORY:使用当前事务运行,如果不存在事务,就抛出异常
		 * 		PROPAGATION_REQUIRED:如果不存在事务,就新建一个事务运行;如果事务存在,就使用当前事务
		 * 		PROPAGATION_REQUIRES_NEW:如果当前事务存在,就新建一个事务,将原来的事务挂起
		 * 		PROPAGATION_NESTED:
		 *
		 *
		 * 	PROPAGATION_SUPPORTS:没有进行判断处理,因为这个隔离级别是:如果事务存在,就事务运行,如果事务不存在,就非事务运行
		 */
		if (isExistingTransaction(transaction)) {
    
    
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		/**
		 * 3、判断超时时间是否小于-1
		 */
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
    
    
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		/**
		 * 4、代码走到这里,理论上应该是不存在事务,才会走到这里
		 * 当事务不存在的时候,就判断当前配置的事务传播机制是什么,mandatory必须以事务方式运行,没有事务就报错
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
    
    
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		/**
		 * 5、required、required_new、nested这三种情况,在没有事务的情况下,需要开启新事务,所以进行统一的处理即可
		 */
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    
    
			/**
			 * 5.1、suspend是挂起线程的意思,这里由于不存在线程,所以传null即可
			 */
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
    
    
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
    
    
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				/**
				 * 5.2、开启一个新的事务,这个方法十分重要
				 */
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
    
    
				resume(null, suspendedResources);
				throw ex;
			}
		}
		/**
		 * 6、代码执行到这里,说明当前不存在事务,且事务的传播机制也不是上面四种
		 * 	PROPAGATION_REQUIRED
		 * 	PROPAGATION_REQUIRES_NEW
		 * 	PROPAGATION_NESTED
		 * 	PROPAGATION_MANDATORY
		 *
		 *
		 * 	剩下的三种都是在非事务方法中运行、或者是没有事务,就以非事务方法运行的
		 * 	support
		 * 	not_support
		 * 	never
		 */
		else {
    
    
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
    
    
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

在这个方法中,大致就是这么几个步骤
1、获取当前事务,这里获取当前事务和后面开启事务有关系,并且用到了threadLocal
2、然后根据当前是否存在事务来判断要进行不同的传播机制的判断

1、获取事务

@Override
	protected Object doGetTransaction() {
    
    
		// 1.创建一个数据源事务对象,将当前事务放入到txObject中
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		/**
		 * 2.设置是否允许嵌套事务
		 * 在初始化DataSourceManager的时候会执行为true
		 */
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		/**
		 * 3.从TransactionSynchronizationManager
		 * 中获取到对应的数据库连接信息,第一次理论上是拿不到对象的,因为是在购买doBegin()
		 * 方法中调用TransactionSynchronizationManager的bindResource()方法的
		 */
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

这个方法就是把已经开启的事务放入到txObject中,如果是 第一次进入到这个方法中,此时是不存在事务的

2、判断是否存在事务

/**
	 * 这里是判断是否存在事务,这个txObject只有在开启一个事务的时候,才会将connection以及事务信息存入到该对象中
	 * 所以:判断当前是否存在事务,就只需要判断connectionHolder是否非null,且active为true
	 * @param transaction transaction object returned by doGetTransaction
	 * @return
	 */
	@Override
	protected boolean isExistingTransaction(Object transaction) {
    
    
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}

这里判断是否存在事务的时候,就是判断第一点中,放入到txObject对象中的connectionHolder是否为null,且active为true;如果同时满足这两个条件,我们就认为当前存在事务,否则不存在事务

3、存在事务

/**
	 * Create a TransactionStatus for an existing transaction.
	 * PROPAGATION_NEVER
	 * PROPAGATION_NOT_SUPPORTED
	 * PROPAGATION_REQUIRES_NEW
	 * PROPAGATION_NESTED
	 * 进入到这个代码的前提是当前存在事务
	 */
	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
    
    

		/**
		 * 1、方法运行到这里,说明当前是有事务的
		 * PROPAGATION_NEVER:是以非事务运行,如果存在事务,就报错
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
    
    
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}

		/**
		 * 2、以非事务方式运行,如果当前存在事务,就将事务挂起,然后以非事务方式运行
		 * 这里牵扯到一个事务挂起的操作
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
    
    
			if (debugEnabled) {
    
    
				logger.debug("Suspending current transaction");
			}
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		/**
		 * 3、新建事务,如果当前存在事务,就将事务挂起
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    
    
			if (debugEnabled) {
    
    
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
			/**
			 * 这里是挂起事务的操作,挂起事务的话,会把事务管理器中的属性设置为null
			 * ,然后将事务管理器中的属性暂时存储到suspendedResourceHolder中
			 */
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
    
    
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error beginEx) {
    
    
				/**
				 * 如果在开启新的事务的时候,异常了,就会在下面这个方法中,将事务恢复(和上面挂起是相对的)
				 * ,其实就是把suspendResourceHolder中的属性重新赋值到TransactionSynchronizationManager
				 */
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}

		/**
		 * 4、如果事务存在,就在嵌套事务内运行,如果事务不存在,就创建一个新的事务
		 */
		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.
				//创建一个新的事务
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, null);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
		}

		/**
		 * 代码如果执行到这里,说明当前有事务,且传播机制不是上面这几个
		 * 	PROPAGATION_NESTED
		 * 	PROPAGATION_REQUIRES_NEW
		 * 	PROPAGATION_NEVER
		 * 	PROPAGATION_NOT_SUPPORTED
		 *
		 * 	剩下的三个
		 * 		required
		 * 		support
		 * 		MANDATORY
		 * 		都是必须以事务运行的
		 *
		 */
		// 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);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

这是存在事务的处理方法,主要的分支代码就是以下几个
1、如果是PROPAGATION_NEVER,就直接抛出异常
2、如果是PROPAGATION_NOT_SUPPORTED,就将当前事务挂起,然后以非事务方法运行
3、如果是PROPAGATION_REQUIRES_NEW,就将事务挂起,然后开启一个新的事务
4、如果是PROPAGATION_NESTED,如果允许嵌套事务运行,就嵌套事务运行,如果不允许,就创建一个新的事务
5、其他传播机制,就在当前事务方法中运行

4、不存在事务

上面源码中

事务传播机制的处理

这里的源码中,第三点开始,是对不存在事务的场景进行的处理。需要注意的是,下面的这个逻辑是在不存在事务的前提下
1、如果是PROPAGATION_MANDATORY,就抛出异常,因为这个传播机制必须以事务方法运行
2、如果是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED这三个,就需要开启新的事务
3、support、not_support、never这三个,是以非事务运行的,所以无需做其他处理

5、开启事务

在上面3和4的这个过程中,需要涉及到两个概念,分别是事务挂起和事务开启

/**
	 * This implementation sets the isolation level but ignores the timeout.
	 *
	 * 这里是开启事务的方法,主要完成了以下的操作
	 */
	@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
    
    
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
    
    
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
    
    
				/**
				 * 1.获取一个数据库连接
				 */
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				/**
				 * 2.然后将连接存入到txObject中;这里的txObject在前面是否存在事务的时候,会用到
				 * isExistTransaction()方法
				 */
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			/**
			 * 设置事务的隔离级别?
			 */
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);

			// 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).
			/**
			 * 3.设置为非自动提交
			 */
			if (con.getAutoCommit()) {
    
    
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			/**
			 * 4.设置事务为只读  set transaction read only
			 * 然后设置事务为active状态
			 * 最重要的是:需要将事务信息绑定到TransactionSynchronizationManager中
			 */
			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);

			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
    
    
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			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);
		}
	}

这里最主要的几个操作:
1、获取一个connection,然后将自动提交设置为false
2、设置事务的隔离级别
3、将transactionActive属性设置为true
4、将事务信息绑定到TransactionSynchronizationManager中,在其内部,是通过threadLocal来完成的

这里的3和4就和前面判断是否存在事务相关联起来了
可以看到在这个方法中所谓的绑定,就是通过bindResource来完成的,在前面第一点获取事务的时候,是通过getResource来获取的

所以:开启事务,就是获取一个connection,然后将其事务绑定到TransactionSynchronizationManager中

6、挂起事务

在事务挂起和开启事务这两个操作中,有两个关键的类:

TransactionSynchronizationManager和SuspendedResourcesHolder

我的理解是:TransactionSynchronizationManager中存储的是事务的相关信息,SuspendedResourcesHolder是用来存放挂起事务的相关信息,所以,所谓的挂起事务,就是把事务信息从一个类中TransactionSynchronizationManager,存入到了SuspendedResourcesHolder中,这样,当前事务就为空,就可以接着开启新的事务,然后在恢复事务的时候,将SuspendedResourcesHolder中暂存的事务信息恢复到TransactionSynchronizationManager中

这就是我对挂起事务和恢复事务的理解,在事务提交或者异常回滚的时候,都会调用恢复事务的方法

@Nullable
	protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
    
    
		/**
		 * 1.如果当前事务是active状态,就将事务挂起,挂起的操作其实也简单
		 * 将当前事务的属性信息暂存到SuspendedResourcesHolder中,然后将当前事务的属性设置为null
		 */
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
    
    
			List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
			try {
    
    
				Object suspendedResources = null;
				if (transaction != null) {
    
    
					suspendedResources = doSuspend(transaction);
				}
				/**
				 * 下面就是挂起事务的操作,将事务同步管理器中的属性置为null
				 * ,然后将配置信息,存储到suspendedResources中,以便在恢复事务的时候,可以恢复
				 */
				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);
				return new SuspendedResourcesHolder(
						suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
			}
			catch (RuntimeException | Error ex) {
    
    
				/**
				 * 2.如果挂起事务失败,就需要进行回滚,就是将suspendedResourcesHolder
				 * 中的属性重新赋值到TransactionSynchronizationManager中
				 */
				// 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;
		}
	}

猜你喜欢

转载自blog.csdn.net/CPLASF_/article/details/112168261