Spring事物传播特性源码分析

本文深入解析了事务传播行为的不同选项,如PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS等,及其在事务管理中的作用。详细解释了在不同情况下,如当前是否存在事务,如何选择合适的传播行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行PROPAGATION_REQUIRED类似的操作。

 

	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		//获取事物对象(内置conection)
		Object transaction = doGetTransaction();

		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			definition = new DefaultTransactionDefinition();
		}

		//这里判断是否已经存在一个事物,如果存在走其他逻辑
		if (isExistingTransaction(transaction)) {
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		//使用当前的事务,如果当前没有事务,就抛出异常
		//代码走到这里,说明isExistingTransaction返回false,当前上下文没有事物。
		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) {
			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);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			//PROPAGATION_SUPPORTS,支持当前事务,如果当前没有事务,就以非事务方式执行。
			//下面是如果当前没有事物,就创建一个空事物。其实就是已非事物方式执行。
			// 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);
		}
	}

上面代码主要是在当前上下文没有事物的情况下的处理逻辑,

如果PROPAGATION_MANDATORY,则抛出异常

如果PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED,则创建一个新事物。

最后就是PROPAGATION_SUPPORTS,有就支持,没有就已非事物运行。

 

 

	/**
	 * Create a TransactionStatus for an existing transaction.
	 */
	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);

			//返回空事物
			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 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_REQUIRED类似的操作
		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);
				//所谓嵌套事物,其实就是JDBC的还原点,在当前位置创建还原点,
				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;
			}
		}

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

上面代码大题逻辑就是如果已经存在一个事物,那么如何处理的逻辑。

 

 

<think>好的,用户现在想了解Spring事务的传播特性。我需要根据之前提供的引用内容来详细解答这个问题。首先,我应该回顾用户提供的引用材料,确保信息的准确性。用户提供的引用[1]、[2]、[3]、[4]、[5]都涉及到Spring事务的不同方面,特别是传播特性和配置方法。 首先,我需要明确Spring事务传播特性的定义和作用。根据引用[2],事务的传播特性通过@Transactional注解的propagation属性设置,而Propagation枚举类对应不同的传播行为。用户可能需要知道每个传播行为的具体含义和使用场景。 接下来,我需要列举并详细解释每个传播特性。例如,PROPAGATION_REQUIRED是默认的,如果当前没有事务,就新建一个,如果有则入。这适用于大多数情况。而PROPAGATION_REQUIRES_NEW则是无论当前是否存在事务,都新建一个,这在需要独立事务时使用,比如日志记录。 同时,用户可能关心这些传播特性如何在实际代码中应用。例如,引用[2]提到使用@Transactional注解来设置,而引用[4]展示了如何通过配置类来管理事务,比如DataSourceTransactionManager。此外,引用[3]提到了JpaTransactionManager的配置,说明不同的持久化框架可能需要不同的事务管理器。 另外,用户可能对事务的回滚机制感兴趣。引用[5]详细描述了异常时的回滚过程,提到在completeTransactionAfterThrowing方法中处理回滚,这可能涉及到检查异常类型,默认情况下Spring只对RuntimeException和Error回滚,用户可能需要配置rollbackFor属性来覆盖其他异常。 还需要注意,用户之前的问题是关于SpringBoot的优缺点,现在转向事务传播特性,可能需要稍微调整回答的侧重点,但保持技术深度。需要确保回答结构清晰,分点解释,并给出代码示例或配置示例,帮助用户理解。 最后,生成相关问题时要覆盖用户可能进一步询问的方向,比如如何选择传播特性、不同场景的应用、配置方法以及异常处理等。确保引用正确的来源,比如在解释传播特性时引用[2]和[4],在配置事务管理器时引用[3]和[4],在回滚机制时引用[5]。 总结下来,回答需要包括传播特性的定义、七种传播行为的详细解释、配置方式(注解和XML)、以及实际应用中的注意事项,如异常回滚和事务管理器选择。同时,使用代码示例和配置片段来增强说明,确保用户能够结合实际代码理解概念。</think>#### Spring事务传播特性详解 Spring事务传播特性定义了**多个事务方法相互调用时,事务如何传播**的逻辑规则,是保证数据一致性的核心机制[^2][^4]。以下详解7种传播行为及其应用场景: --- ### 一、传播特性定义与配置 1. **核心枚举类**:通过`Propagation`枚举定义7种传播行为,对应`TransactionDefinition`接口常量。 2. **配置方式**: - **注解配置**:在方法上使用`@Transactional(propagation = Propagation.REQUIRED)`[^2]。 - **XML配置**:通过`<tx:method>`标签指定传播行为[^3]。 --- ### 二、7种传播行为解析 | **传播行为** | **触发条件** | **典型场景** | |---------------------------|-----------------------------------------------------------------------------|---------------------------------------| | **REQUIRED**(默认) | 当前无事务→新建事务;当前有事务→入该事务 | 通用型业务方法(如订单支付)[^2][^4] | | **SUPPORTS** | 当前无事务→非事务执行;当前有事务→入该事务 | 查询方法(可适应事务或非事务环境) | | **MANDATORY** | 当前无事务→抛出异常;当前有事务→入该事务 | 强制要求调用方必须开启事务的方法 | | **REQUIRES_NEW** | 无论当前是否有事务→始终新建独立事务,暂停原事务(若存在) | 日志记录、审计等独立操作[^2] | | **NOT_SUPPORTED** | 当前无事务→非事务执行;当前有事务→挂起原事务,非事务执行 | 需要绕过事务的方法(如调用外部API) | | **NEVER** | 当前无事务→非事务执行;当前有事务→抛出异常 | 禁止在事务中调用的方法(如数据校验) | | **NESTED** | 当前无事务→新建事务;当前有事务→创建嵌套事务(可部分回滚) | 复杂业务分层(如主流程与子流程) | --- ### 三、关键机制与源码分析 1. **事务嵌套与保存点** - **NESTED传播**依赖数据库的保存点(Savepoint)机制,允许子事务回滚不影响外层事务[^4]。 - 示例:主事务提交订单,嵌套事务扣减库存。若库存不足,仅回滚嵌套事务,不影响订单提交[^4]。 2. **事务挂起与恢复** - **REQUIRES_NEW**传播时,Spring通过`TransactionSynchronizationManager`挂起当前事务,创建新事务[^2]。 ```java // 伪代码示例:挂起当前事务 SuspendedResourcesHolder suspendedResources = suspend(existingTransaction); try { // 创建新事务 DefaultTransactionStatus newStatus = startTransaction(definition, transaction, debugEnabled, suspendedResources); // 执行业务逻辑 return invokeWithinTransaction(...); } finally { // 恢复原事务 resume(suspendedResources, existingTransaction); } ``` 3. **异常回滚规则** - 默认仅对`RuntimeException`和`Error`回滚,需通过`@Transactional(rollbackFor = Exception.class)`扩展[^5]。 - 回滚逻辑:调用链`TransactionAspectSupport.completeTransactionAfterThrowing()`→`AbstractPlatformTransactionManager.rollback()`→底层JDBC `Connection.rollback()`[^5]。 --- ### 四、配置与实战示例 1. **注解配置案例** ```java @Service public class OrderService { @Autowired private InventoryService inventoryService; @Transactional(propagation = Propagation.REQUIRED) public void createOrder(Order order) { // 主事务:保存订单 orderRepository.save(order); // 嵌套事务:扣减库存(独立回滚) inventoryService.deductStock(order.getProductId(), Propagation.NESTED); } } ``` 2. **XML配置案例** ```xml <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> ``` --- ### 五、常见问题与解决方案 1. **事务不生效** - 原因:未启用事务管理(需添`@EnableTransactionManagement`)、方法非public、同类内方法调用(绕过代理)[^3]。 - 解决:使用AspectJ模式或通过代理对象调用方法。 2. **嵌套事务回滚范围** - **NESTED传播**仅回滚嵌套事务内的操作,而**REQUIRES_NEW**完全独立(外层事务回滚不影响内层)[^4]。 --- ### 六、总结 - **选择依据**:根据业务逻辑的隔离性需求、数据一致性级别、性能要求综合判断。 - **最佳实践**:优先使用默认`REQUIRED`,需要强隔离时用`REQUIRES_NEW`,分层业务用`NESTED`[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值