死磕Spring之AOP篇 - Spring 事务详解 (11)

整个过程关键在于第 3 步将 autocommit 设置为 false,不会自动提交,这样一来,可以在一个事务中根据行为作出相应的操作,例如出现异常进行回滚,没有问题则进行提交

接下来我们来看看 Spring 对于当前线程正处于一个事务中时,如何进行处理的

1.3 handleExistingTransaction 方法

handleExistingTransaction(..) 方法,处理已存在事务的情况,如下:

// AbstractPlatformTransactionManager.java private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { // <1> 如果是 **NEVER** 事务传播级别,因为当前线程正处于一个事务中,此时抛出异常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation 'never'"); } // <2> 否则,如果是 **NOT_SUPPORTED** 事务传播级别,因为当前线程正处于一个事务中,此时挂起事务 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { // <2.1> 事务挂起,也就是从 ThreadLocal 中移除各种对象,并返回一个挂起的资源对象(包含所有被移除的对象) Object suspendedResources = suspend(transaction); // 是否需要一个创建一个事务同步器(默认为 true) boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); // <2.2> 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性,包括被挂起的资源 // 设置 `transaction` 为 null(当前没有事务),`newTransaction` 为 `false`,表示不是一个新的事务 // 同时借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量 return prepareTransactionStatus( definition, null, false, newSynchronization, debugEnabled, suspendedResources); } // <3> 否则,如果是 **REQUIRES_NEW** 事务传播级别(无论如何都会创建一个新的事务),因为当前线程正处于一个事务中,此时挂起当前事务,创建一个新的事务 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { // <3.1> 事务挂起,也就是从 ThreadLocal 中移除各种对象,并返回一个挂起的资源对象(包含所有被移除的对象) SuspendedResourcesHolder suspendedResources = suspend(transaction); try { // 是否需要一个创建一个事务同步器(默认为 true) boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // <3.2> 创建一个事务状态对象,设置相关属性,包括被挂起的资源 // 设置 `newTransaction` 为 `true`,表示是一个新的事务 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); // <3.3> 【关键】执行 begin 操作,如果没有 Connection 数据库连接,则通过 DataSource 创建一个新的连接 // 设置 Connection 的隔离级别、是否只读,并执行 Connection#setAutoCommit(false) 方法,不自动提交 // 同时将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中 doBegin(transaction, definition); // <3.4> 借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量 prepareSynchronization(status, definition); // <3.5> 返回上面创建的 DefaultTransactionStatus 事务状态对象 return status; } catch (RuntimeException | Error beginEx) { // 在抛出异常前唤醒刚才被挂起的资源 resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } } // <4> 否则,如果是 **NESTED** 事务传播级别(执行一个嵌套事务),还是使用当前线程的事务,不过设置了保存点,相当于一个嵌套事务,在 Mysql 中是采用 SAVEPOINT 来实现的 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'"); } // <4.1> 如果支持使用保存点(默认为 true) 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); // 创建一个保存点,调用 Connection#setSavepoint(String) 方法 status.createAndHoldSavepoint(); return status; } // <4.2> 否则,例如 JtaTransactionManager(JTA 事务),暂时忽略 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); // 执行 begin 操作,暂时忽略 doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } } // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED. // <5> 走到这里了,表示就使用当前已存在的事务,例如 **REQUIRED** 传播级别 // <6> 判断定义的 IsolationLevel 和已存在的事务的 IsolationLevel 进行校验(默认为 false) 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"); } } } // 是否是一个新的事务同步器(默认为 true) boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // <7> 创建一个 DefaultTransactionStatus 事务状态对象 // 设置 `newTransaction` 为 `false`,表示不是一个新的事务 // 同时借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量 // 注意这里用的 `definition` 是当前 `@Transactional` 注解的相关属性,所以隔离级别等属性是当前定义的,而不是当前已存在的事务的隔离级别 return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null); }

整个过程如下:

如果是 NEVER 事务传播级别,因为当前线程正处于一个事务中,此时抛出异常

否则,如果是 NOT_SUPPORTED 事务传播级别,因为当前线程正处于一个事务中,此时挂起事务,不使用事务

调用 suspend(..) 方法,将当前事务挂起,也就是从 ThreadLocal 中移除各种对象,并返回一个挂起的资源对象(包含所有被移除的对象)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygsff.html