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

为本地方法的执行创建一个事务,过程比较复杂,可以先理解为需要把 Connection 连接的 autocommit 关闭,然后根据 @Transactional 注解的属性进行相关设置,例如根据事务的传播级别判断是否需要创建一个新的事务

事务准备好了,那么继续执行方法调用器,也就是方法的执行

捕获到异常,进行回滚,或者提交(异常类型不匹配)

正常情况,走到这里就完成事务,调用 Connection 的 commit() 方法完成本次事务(不是一定会执行,因为可能是“嵌套事务”或者“逻辑事务”等情况)

接下来,我们一起来看看 Spring 是如何创建一个事务的

1. 创建事务

createTransactionIfNecessary(..) 方法,创建一个事务(如果有必要的话),如下:

// TransactionAspectSupport.java protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { // <1> 没有设置事务名称,则封装成一个 DelegatingTransactionAttribute 委托对象,支持返回一个事务名称(类名.方法名) if (txAttr != null && txAttr.getName() == null) { txAttr = new DelegatingTransactionAttribute(txAttr) { @Override public String getName() { return joinpointIdentification; } }; } // <2> 获取一个 TransactionStatus 对象 TransactionStatus status = null; if (txAttr != null) { // <2.1> 如果存在事务管理器 if (tm != null) { // 从事务管理器中获取一个 TransactionStatus 事务状态对象(对事务的封装),该对象包含以下信息: // TransactionDefinition 事务定义、DataSourceTransactionObject 数据源事务对象(包括 DataSource 和 Connection)、 // 是否是一个新的事务、是否是一个新的事务同步器、被挂起的事务资源对象 status = tm.getTransaction(txAttr); } // <2.2> 否则,跳过 else { } } // <3> 创建一个 TransactionInfo 事务信息对象,并绑定到 ThreadLocal 中 return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }

过程如下:

如果没有设置事务名称,则封装成一个 DelegatingTransactionAttribute 委托对象,支持返回一个事务名称(类名.方法名)

获取一个 TransactionStatus 对象(对事务的封装)

如果存在事务管理器,Spring Boot 中默认为 DataSourceTransactionManager,则通过事务管理器根据 @Transactional 注解获取一个 TransactionStatus 事务状态对象,该对象是对事务的封装,包含了以下信息:

TransactionDefinition 事务定义

DataSourceTransactionObject 数据源事务对象(包括 DataSource 和 Connection)

是否是一个新的事务

是否是一个新的事务同步器

被挂起的事务资源对象(如果有)

否则,跳过

创建一个 TransactionInfo 事务信息对象,并绑定到 ThreadLocal 中,如下:

// TransactionAspectSupport.java protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { // <1> 创建一个 TransactionInfo 对象 TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification); // <2> 如果有 @Transactional 注解的元信息 if (txAttr != null) { // 设置 DefaultTransactionStatus 事务状态对象 txInfo.newTransactionStatus(status); } else { } // We always bind the TransactionInfo to the thread, even if we didn't create // a new transaction here. This guarantees that the TransactionInfo stack // will be managed correctly even if no transaction was created by this aspect. // <3> 将当前 TransactionInfo 对象保存至 ThreadLocal 中 txInfo.bindToThread(); // <4> 返回这个 TransactionInfo 对象 return txInfo; }

可以看到,即使没有创建事务,也会创建一个 TransactionInfo 对象,并绑定到 ThreadLocal 中

我们继续看到在上面第 2 步 PlatformTransactionManager 事务管理器是如何创建一个 Spring 事务的

1.1 getTransaction 方法

PlatformTransactionManager 事务管理器接口的类图:

死磕Spring之AOP篇 - Spring 事务详解

该接口就定义了三个方法,如下:

public interface PlatformTransactionManager { TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }

三个方法分别对应创建事务,提交,回滚三个操作,关于 Spring 事务也就这三个核心步骤了,我们先来看看 getTransaction(..) 这个方法的实现,如下:

// AbstractPlatformTransactionManager.java @Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { // <1> 先从当前事务管理器中获取 DataSource 对象,然后尝试以它作为一个 Key 从一个 ThreadLocal 的 Map 中获取对应的 ConnectionHolder 连接对象 // 会包装成一个 DataSourceTransactionObject 对象返回 Object transaction = doGetTransaction(); // Cache debug flag to avoid repeated checks. boolean debugEnabled = logger.isDebugEnabled(); // <2> 如果没有 @Transactional 注解对应的元信息,则创建一个默认的 TransactionDefinition 对象 if (definition == null) { // Use defaults if no transaction definition given. definition = new DefaultTransactionDefinition(); } // <3> 如果上面 `transaction` 数据源事务对象已有 Connection 连接,且正处于一个事务中,表示当前线程已经在一个事务中了 if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. // <3.1> 根据 Spring 事务传播级别进行不同的处理,同时创建一个 DefaultTransactionStatus 事务状态对象,包含以下信息: // TransactionDefinition 事务定义、DataSourceTransactionObject 数据源事务对象、 // 是否需要新创建一个事务、是否需要一个新的事务同步器、被挂起的事务资源对象 return handleExistingTransaction(definition, transaction, debugEnabled); } // <4> 否则,当前线程没有事务 // 超时不能小于默认值 if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } // <4.1> 如果是 **MANDATORY** 事务传播级别(当前线程已经在一个事务中,则加入该事务,否则抛出异常),因为当前线程没有事务,此时抛出异常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } // <4.2> 否则,如果事务传播级别为 **REQUIRED|REQUIRES_NEW|NESTED** else if ( // 如果当前线程已经在一个事务中,则加入该事务,否则新建一个事务(默认) definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || // 无论如何都会创建一个新的事务,如果当前线程已经在一个事务中,则挂起当前事务,创建一个新的事务 definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || // 执行一个嵌套事务 definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { // <4.2.1> 创建一个“空”的挂起资源对象 SuspendedResourcesHolder suspendedResources = suspend(null); try { // 是否需要新的事务同步器,默认为 true boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // <4.2.2> 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性 // 这里 `newTransaction` 参数为 `true`,表示是一个新的事务 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); // <4.2.3> 【关键】执行 begin 操作,如果没有 Connection 数据库连接,则通过 DataSource 创建一个新的连接 // 设置 Connection 的隔离级别、是否只读,并执行 Connection#setAutoCommit(false) 方法,不自动提交 // 同时将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中 doBegin(transaction, definition); // <4.2.4> 借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量 prepareSynchronization(status, definition); // <4.2.5> 返回上面创建的 DefaultTransactionStatus 事务状态对象 return status; } catch (RuntimeException | Error ex) { resume(null, suspendedResources); throw ex; } } // <4.3> 否则,创建一个“空”的事务状态对象 else { // 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); } // 是否需要新的事务同步器,默认为 true boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); // 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性,这里也是一个新的事务 return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); } }

整个过程如下:

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

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