Spring事务传播特性 Spring源码解析之事务传播特性
为啥我就不胖呢 人气:0想了解Spring源码解析之事务传播特性的相关内容吗,为啥我就不胖呢在本文为您仔细讲解Spring事务传播特性的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Spring事务传播特性,Java事务传播行为,下面大家一起来学习吧。
一、使用方式
可以采用Transactional,配置propagation即可。
打开org.springframework.transaction.annotation.Transactional
可见默认传播特性是REQUIRED
。
/** * The transaction propagation type. * <p>Defaults to {@link Propagation#REQUIRED}. * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() */ Propagation propagation() default Propagation.REQUIRED;
二、getTransaction
顾名思义,此项属性是在事务存在交互时生效。那么到底是如何生效的呢,核心源码位于org.springframework.transaction.support.AbstractPlatformTransactionManager
。核心入口是getTransaction方法。
@Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { 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(); } //已经存在事务 根据事务传播特性进行处理 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. 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. //当前不存在事务 MANDATORY直接抛出异常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } //REQUIRED REQUIRES_NEW 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 { xxx } }
可以看到,在当前不存在事务时,
- MANDATORY 直接抛出异常
- REQUIRED REQUIRES_NEW NESTED 自动新建一个事务。
那么存在事务时是如何处理的呢?
三、handleExistingTransaction
/** * 处理已经存在事务的情况 * Create a TransactionStatus for an existing transaction. */ 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 注意prepareTransactionStatus方法参数传递事务的时候传递参数为null,所以是采用非事务方式运行。执行会挂起当前事务。 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 { 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; } } //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()) { // 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); //注意此处会创建savePoint 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); // 注意此处newTransaction属性设置为true,说明确实采用了创建新事务方式来实现 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); }
可以看到,当已经存在事务时,
- NEVER 直接报错,不支持事务
- NOT_SUPPORTED 默默按照非事务方式运行
- REQUIRES_NEW 新建一个事务。
- NESTED 处理嵌套事务 视情况采用savePoint或者新建事务。
- 其他的 加入当前事务
四、NESTED 嵌套事务
SavePoint
先简单说说SavePoint机制吧。这个也比较简单。
比如一个 事务比较复杂,容易出错。那么如果当前DB支持SavePoint的话,那么创建一个SavePoint就等于创建了一个快照,可以不用每次都回滚整个事务,仅回滚到指定的SavePoint即可。
五、个人理解
NESTED这个处理确实比较复杂。个人也查了很多资料。目前个人目前理解如下:
NESTED对于事务的处理主要在于级别不同。
REQUIRES_NEW创建的两个事务是平级的,一个事务的成功与否对另一个事务的成功与否不产生影响。
而NESTED创建的事务则名副其实,是受其父级事务影响的。
一句话总结就是,子事务的成功与否不影响父级事务的成功,但是父级事务的成功与否则会影响子事务的成功。
父事务回滚,子事务一定会滚。
子事务回滚,父事务不一定会滚。
六、总结
最后总结如下
名称 | 说明 |
PROPAGATION_REQUIRED | 方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。 默认选项。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。 |
加载全部内容