【源码】Spring事务之传播特性的详解

Spring事务系列

1、【源码】SpringBoot事务注册原理

2、【源码】Spring Data JPA原理解析之事务注册原理

3、【源码】Spring Data JPA原理解析之事务执行原理

4、【源码】SpringBoot编程式事务使用及执行原理

5、【源码】Spring事务之传播特性的详解

6、【源码】Spring事务之事务失效及原理

前言

《Spring事务系列》的前面4篇博文从源码的角度分析了Spring事务的注册以及执行原理,本篇分享一下事务的传播特性。

事务传播特性

Spring事务包含七种的传播特性,在Propagation枚举类中,分别如下:

1)REQUIRE:如果当前没有事务,则新创建一个事务;如果上下文存在事务,则加入到这个事务中。默认值;

2)SUPPORTS:如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则使用无事务的方式执行。即:如果上下文有事务,则加入这个事务;否则直接执行,不会新创建事务;

3)MANDATORY:如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则报错;

4)REQUIRES_NEW:每次都新创建一个事务。如果当前上下文有事务,则挂起上下文的事务,重新创建一个事务;如果当前上下文没有事务,新创建一个事务;

如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用REQUIRES_NEW传播特性。如果ServiceB.method()提交后,ServiceA.method()报错,则ServiceB.method()不会回滚,ServiceA.method()会回滚;如果ServiceB.method()报错,则ServiceA.method()可以通过捕获异常,选择回滚或提交。

5)NOT_SUPPORTED:不支持事务执行。如果当前上下文存在事务,则挂起上下文事务;

如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NOT_SUPPORTED传播特性,则ServiceB.method()的执行不在事务范围内。如果ServiceB.method()报错,则ServiceA.method()可以通过捕获异常,选择回滚或提交。

6)NEVER:无事务执行。如果当前上下文存在事务,则抛异常;

如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NEVER传播特性,则ServiceB.method()的整条调用链中都不能创建事务,否则会报错。

7)NESTED:嵌套事务。如果上下文存在事务,则在嵌套的事务中执行;如果上下文没有事务,则新创建一个事务;

如:ServiceA.method()调用ServiceB.method(),在ServiceB.method()使用NESTED传播特性。如果ServiceB.method()报错,则只回滚ServiceB.method()中的信息,对ServiceA.method()没有影响。通过savepoint实现。

源码解析

事务的传播特性可以通过@Transactional注解的propagation属性进行设置,对于Propagation枚举类中每一种传播特性,在TransactionDefinition中都对应一个属性值。

3.1 Propagation

Propagation的源码如下:

public enum Propagation {
	
	// 需要事务。如果当前没有事务,则新创建一个事务;如果上下文存在事务,则加入到这个事务中。默认值;
	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

	// 如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则使用无事务的方式执行。即:如果上下文有事务,则加入这个事务;否则直接执行,不会新创建事务;
	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

	// 如果当前上下文存在事务,则加入这个事务;如果上下文不存在事务,则报错;
	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

	// 每次都新创建一个事务。如果当前上下文有事务,则挂起上下文的事务,重新创建一个事务;如果当前上下文没有事务,新创建一个事务;
	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
	
	// 不支持事务执行。如果当前上下文存在事务,则挂起上下文事务;
	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

	// 无事务执行。如果当前上下文存在事务,则抛异常;
	NEVER(TransactionDefinition.PROPAGATION_NEVER),

	// 嵌套事务。如果上下文存在事务,则在嵌套的事务中执行;如果上下文没有事务,则新创建一个事务;
	NESTED(TransactionDefinition.PROPAGATION_NESTED);


	private final int value;


	Propagation(int value) {
		this.value = value;
	}

	public int value() {
		return this.value;
	}

}

3.2 传播特性判断

Spring事务中的传播特性在AbstractPlatformTransactionManager类中进行判断,详见

【源码】Spring Data JPA原理解析之事务执行原理-CSDN博客

传播特性判断的核心代码如下:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		// 抽象方法。如JpaTransactionManager.doGetTransaction(),创建一个JpaTransactionObject对象,开启一个新的Connection
		Object transaction = doGetTransaction();

		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			definition = new DefaultTransactionDefinition();
		}
		// 如果事务存在,则检测传播行为并返回
		if (isExistingTransaction(transaction)) {
			// 找到现有事务->检查传播行为以了解行为方式
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// 检查事务属性中的超时属性,默认为-1
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// 如果事务的传播特性为PROPAGATION_MANDATORY,则抛异常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		// 如果事务的传播特性为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED,
		// 此时没有事务,所以需要创建新的事务
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			// 挂起事务,此处返回的suspendedResources为null
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				// 初始getTransactionSynchronization()为0,需要激活事务同步
				// SYNCHRONIZATION_NEVER为2,表示不激活事务同步
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				// 创建一个DefaultTransactionStatus对象,传入刚创建的transaction对象,新开启一个连接
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 开始事务
				doBegin(transaction, definition);
				// 准备同步,将事务相关信息保存到本地线程变量
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 传播特性为PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER,此时没有事务,则不开启事务执行
			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);
			// 创建一个DefaultTransactionStatus对象,此处的transaction为null
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

	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");
			}
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 创建一个DefaultTransactionStatus对象,此处的transaction为null
			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 {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				// 创建一个DefaultTransactionStatus对象,此处的transaction为新创建的事务
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 开启事务
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}
		// 如果事务的传播特性为PROPAGATION_NESTED,因为上下文存在事务,则使用嵌套事务
		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() + "]");
			}
			// 如果支持savepoint保存点,则创建保存点
			if (useSavepointForNestedTransaction()) {
				DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				status.createAndHoldSavepoint();
				return status;
			}
			else { // 否则的话,创建新的事务
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, null);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
		}

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

}

事务的传播特性判断在AbstractPlatformTransactionManager的getTransaction()和handleExistingTransaction()方法。

3.2.1 getTransaction()

getTransaction()方法主要执行如下:

1)执行抽象方法doGetTransaction(),获取一个事务对象。如如JpaTransactionManager.doGetTransaction(),创建一个JpaTransactionObject对象,开启一个新的Connection;

2)判断上下文是否存在事务,如果有,则执行handleExistingTransaction()方法;

3)如果没有事务,执行如下:

3.1)如果事务的传播特性为PROPAGATION_MANDATORY,则抛异常;

3.2)如果事务的传播特性为PROPAGATION_REQUIRED或PROPAGATION_REQUIRES_NEW或PROPAGATION_NESTED,此时没有事务,所以需要创建新的事务;

3.3)否则,传播特性为PROPAGATION_SUPPORTS或PROPAGATION_NOT_SUPPORTED或PROPAGATION_NEVER,此时没有事务,则不开启事务,继续执行;

3.2.2 handleExistingTransaction()

handleExistingTransaction()执行时,说明当前上下文存在事务,方法主要执行如下:

1)如果事务的传播特性为PROPAGATION_NEVER,因为上下文存在事务,则抛异常;

2)如果事务的传播特性为PROPAGATION_NOT_SUPPORTED,因为上下文存在事务,则挂起事务,继续执行;

3)如果事务的传播特性为PROPAGATION_REQUIRES_NEW,因为上下文存在事务,则挂起事务,新创建一个事务;

4)如果事务的传播特性为PROPAGATION_NESTED,因为上下文存在事务,则使用嵌套事务;

4.1)如果支持savepoint保存点,则创建保存点。如果保存点中的报异常,则只回滚保存点的事务;

4.2)如果不支持savepoint,则创建新事务;

小结

在实际的项目中,需要根据实际的业务需要,设置合理的传播特性,使用不当,不仅会导致事务失效,还可能导致数据不一致问题。

以上为本篇分享的全部内容,关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值