Spring原理篇(17)--Spring事务的传播机制;该篇章是Spring原理篇的最后一章;

Posted 喜欢编码的老胡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring原理篇(17)--Spring事务的传播机制;该篇章是Spring原理篇的最后一章;相关的知识,希望对你有一定的参考价值。

@TOC# Spring系列
记录在程序走的每一步___auth:huf


由浅入深:
我们再使用@Transctional注解的时候;我们非常喜欢一个动作就是调度方法 直接就xxxx(); 就调度了Bean内的方法; 这种方式 是不起效果的 请注意

如果要事务起效 请用他的代理方法进行调度 那么就会起效; 这个跟事务传播没有关系; 是跟AOP 是否使用了代理对象有关系;


我们前一篇文章 有大量源码. 可能看起来很枯燥. 昨天文章有大量的文字描述原理 也想睡觉; 今天我们图文并茂.先来一段文字: 我们执行对象方法的时候 对象方法如何去开启事务;

1: Spring 事务管理器 创建数据库连接;(跟上章呼应上)
2: conn.setSqlLevel 设置隔离级别;
3: conn.setAuthCommit=false; 关闭自动提交
4: conn.setThreadlocal 它是一个Map 实际上就是把数据库连接 conn放进去;
5: target.sql 对象方法执行;

	如果这里由调用了一个方法 并且方法上有 @Transactional(propagation = Propagation.REQUIRES_NEW)
	关键的来了;
	1)挂起上面一个事务;
	2) Spring 事务管理器 创建数据库连接;
	3) conn.setSqlLevel;设置隔离级别;
	4) conn.setAuthCommit = false;关闭自动提交
	5) conn.setThreadlocal 它是一个Map 实际上就是把数据库连接 conn放进去;
	target.sql
	....又遇到一个事务...又在执行一遍; 
	conn.commit; 或者是 rollback 
	恢复 挂起的事务 ---->把挂起事务放进去Threadlocal

N:conn.commit; 或者是 rollback

原理部分就讲清楚 讲明白了; 下面上源码部分;


因为我们使用了@Trancastional 注解 所以它最终会进来 TransactionInterceptor 也就是上一篇文章 说的Advice 中 执行 invoke方法;


中间的proceed 就是去执行我们的被代理类的代理方法; 在这过程当中; 我们一步一步分析:在Invoke方法中 return invokeWithinTransaction 该方法点进去 我们一路看下去

@Nullable
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {
		"如果事务属性为null,则该方法是非事务性的。"
		TransactionAttributeSource tas = getTransactionAttributeSource();
		"获取propagation 等配置属性 "
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		"获取事务管理器,事务管理器 就是去创建连接  Commit rollback 等一系列操作用的"
		final TransactionManager tm = determineTransactionManager(txAttr);
		"是否是 ReactiveTransactionManager 管理器;目前笔者没有用过这个管理器; "
		"我们在config配置的 是PlatformTransactionManager"
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			"该段代码忽略"
			"该段代码最后肯定是return的"
			return result;
		}
		"事务管理器 : 可以在Config里面进行配置; 只需要传入dataSource() 就可以"
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			"该方法内部有一个开启了事务的核心方法, 下一自然段我们重点看这个方法"
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				"执行被代理对象的代理方法;"
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				"如果报错 进入该方法进行回滚 "
				completeTransactionAfterThrowing(txInfo, ex);
				"抛出异常"
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
												"设置回滚规则,自行配置规则,这里不会诉说"
			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				"仅当Vavr故障与回滚规则匹配时,才进行et回滚"
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}
			"提交事务"
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		"这下面还会return 一种情况"
	}

我们先来看 事务传播机制的规则:

Propagation.MANDATORY   "强制性"
Propagation.NESTED "嵌套"
Propagation.NEVER "从不"
Propagation.NOT_SUPPORTED "不支持"
Propagation.REQUIRED "默认事务"
Propagation.REQUIRES_NEW "从新再开启一个事务" 
Propagation.SUPPORTS "支持" 

在说核心方法之前 我们先知道 在传播机制规则中 我们可以配置这7种规则; 这七种规则 我并没有详细说明或者是直接说明它干什么的. 跟着源码 就知道了

createTransactionIfNecessary()方法

"再其方法内部  这里就是开启事务的核心方法了"
status = tm.getTransaction(txAttr);

getTransaction()方法;

	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {
		"如果没有给出事务定义,则使用默认值。"
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();
		if (isExistingTransaction(transaction)) {
			"判断传播机制 这个方法就解释了我们 的传播机制规则; 下面会详细说"
			return handleExistingTransaction(def, transaction, debugEnabled);
		}
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}
		"注意   Propagation.MANDATORY  强制性  就会抛出异常. 它的作用是 手动的开启事务 "
		"必须要有事务.如果没有事务 就会抛出异常 . 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   TransactionDefinition.PROPAGATION_NESTED "
		"继续往下走."
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			"如果有事务 挂起事务.贴合上面所描述 "
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				" 核心方法 : 开启事务 "
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		....省略部分代码
		}
	}

startTransaction

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

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		"开启事务 看用了什么组件;"
		doBegin(transaction, definition);
		prepareSynchronization(status, definition);
		return status;
	} 


这里 我们用了DataSource

@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		"申明数据库连接"
		Connection con = null; 
		try {
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();
			"设置隔离级别"
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			"设置事务是否可读"
			txObject.setReadOnly(definition.isReadOnly());
		
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				"关闭事务自动提交!"
				con.setAutoCommit(false);
			}
		```省略部分代码
	}

上面那一段源码 匹配上这段文字了

主要是设置autoCommit 为false;

接下来 我们看这个方法
再我们的

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
		"如果是never 就报错 不支持当前有事务 后面会写进去总结里面"
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}
		"NOT_SUPPORTED 意思是不开启新的数据库连接. "
		"我们的事务 实际就是一个一个的数据库连接;我们有两个步骤 一个是先挂起 然后开启新的事务 "
		" 这个就是说  我挂起. 但是不开启新的事务;"
		  "那后面的那个数据库连接 实际上用的就是Jdbc 或者是 Mybatis里面的数据库连接了"
		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);
		}
		"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;
			}
		}
		"PROPAGATION_NESTED 不会去开启新的数据库连接 再数据库里 有一个savepoint的一个说法"
		"也就是设置了这个savepoint 我们可以回滚到 某一个点上 例如 我执行A B C 3个sql"
		"再B sql 上面我们创建了 savepoint 那么 就会回滚到B sql 这里来;"
		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);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

以上 我们就讲解了 事务的传播机制;我们挂起 以及恢复挂起 提交 以及回滚的源码; 并没有详细说道. 这里如果感兴趣的同学 可以去看一下源码;

总结

1:

Propagation.MANDATORY   "强制性"  "强制性要求开启事务 用于手动开启事务"
Propagation.NESTED "嵌套" "回滚到某一个savepoint 的那个点上 不会从新开启数据库连接 "
Propagation.NEVER "从不" "不允许有事务的存在" 
Propagation.NOT_SUPPORTED "不支持" "挂起当前事务,不创建新的事务"
Propagation.REQUIRED "默认事务"
Propagation.REQUIRES_NEW "从新再开启一个事务,与之前事务毫不相关" 
Propagation.SUPPORTS "支持,如果上一个Bean  或者方法 使用了事务 那么就延用事务. 如果没用事务 那么就不用事务" 

2:
Spring开启事务的全部流程

Spring 核心源码 在这里 就结束了;

see you

以上是关于Spring原理篇(17)--Spring事务的传播机制;该篇章是Spring原理篇的最后一章;的主要内容,如果未能解决你的问题,请参考以下文章

Spring事务专题事务的基本概念,Mysql事务处理原理

JDBC与Spring事务及事务传播性原理解析-上篇

JDBC与Spring事务及事务传播性原理解析-上篇

JDBC与Spring事务及事务传播性原理解析-下篇

JDBC与Spring事务及事务传播性原理解析-下篇

Spring原理篇(14)--Spring AOP源码的实现<一>