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 {@Overridepublic final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {// 抽象方法。如JpaTransactionManager.doGetTransaction(),创建一个JpaTransactionObject对象,开启一个新的ConnectionObject transaction = doGetTransaction();boolean debugEnabled = logger.isDebugEnabled();if (definition == null) {definition = new DefaultTransactionDefinition();}// 如果事务存在,则检测传播行为并返回if (isExistingTransaction(transaction)) {// 找到现有事务->检查传播行为以了解行为方式return handleExistingTransaction(definition, transaction, debugEnabled);}// 检查事务属性中的超时属性,默认为-1if (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为nullSuspendedResourcesHolder 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为nullreturn 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为nullreturn 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,则创建新事务;
小结
在实际的项目中,需要根据实际的业务需要,设置合理的传播特性,使用不当,不仅会导致事务失效,还可能导致数据不一致问题。
以上为本篇分享的全部内容,关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。