SpringBoot源码专题-Transaction事务切面

总结摘要
Transaction事务切面

自动配置

概述

@EnableTransactionManagement 开启自动事务

org.springframework.transaction.annotation.EnableTransactionManagement

无论是默认自动配置事务,还是手动添加注解开启事务,都会使用 @EnableTransactionManagement注解。

默认自动配置

配置文件 org.springframework.boot.autoconfigure.AutoConfiguration.importsspring-autoconfigure-metadata.properties

  1. 文件路径 spring-boot-autoconfigure-2.7.18.jar!/META-INF/spring-autoconfigure-metadata.properties
  2. 文件路径spring-boot-autoconfigure-2.7.18-sources.jar!/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

JDBC 数据源与事务相关自动配置类

  1. 全量相关类
    1. org.springframework.boot.autoconfigure.jdbc.*
    2. org.springframework.boot.autoconfigure.transaction.*
  2. 重点类
    1. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
    2. org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
    3. org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

TransactionAutoConfiguration

JdkDynamicAutoProxyConfiguration 与 CglibAutoProxyConfiguration 均使用了注解 @EnableTransactionManagement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
@AutoConfiguration
@ConditionalOnClass(PlatformTransactionManager.class)
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

    // org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration.EnableTransactionManagementConfiguration
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}
	}
}

自动配置手动添加注解

EnableTransactionManagement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// org.springframework.transaction.annotation.EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    // 如果修改该配置,不仅影响 @Transactional 注解修饰的 bean,还会影响 @Async 注解修饰的 bean 等。
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;    
}

// org.springframework.transaction.annotation.TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    // case PROXY: ProxyTransactionManagementConfiguration.class, AutoProxyRegistrar.class
    // case ASPECTJ: "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" or "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"
    // 默认为 PROXY
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
        //...
    }
}

// org.springframework.context.annotation.AdviceModeImportSelector
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
    // 主要功能是解析注解属性,然后调用子类的 org.springframework.context.annotation.AdviceModeImportSelector#selectImports(org.springframework.context.annotation.AdviceMode) 方法。
    @Override
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //...
    }
}   

ProxyTransactionManagementConfiguration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        //...
    }

    // 注册 AnnotationTransactionAttributeSource,其中创建了 SpringTransactionAnnotationParser,用于查找和解析 @Transactional 的属性。
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
        //...
    }
}

// org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName()));
		//...
	}

    // 处理 TransactionManagementConfigurer
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
        //...
    }
    
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}
}
1
2
3
4
5
6
7
8
// org.springframework.context.annotation.AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    // 注册 AOP 类 InfrastructureAdvisorAutoProxyCreator.class,并配置 proxyTargetClass 等属性。
    @Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //...
    }
}

AutoProxyRegistrar#registerBeanDefinitions 方法注册 AOP 类时,底层调用了 org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired。

仅允许注册下列三个 AutoProxyCreator 其中之一,优先级按顺序递增,即 AnnotationAwareAspectJAutoProxyCreator 的优先级是最高的。

这也是 proxyTargetClass 属性同时影响 @Transactional@Async的原因,因为它们底层会使用同一个类实例。

1
2
3
4
5
6
7
8
9
// org.springframework.aop.config.AopConfigUtils
public abstract class AopConfigUtils {
	static {
		// Set up the escalation list...
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}
}

事务 AOP 相关类

Advisor

1
2
3
4
5
// org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {}

// org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {}

Interceptor

1
2
3
// org.springframework.transaction.interceptor.TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
}

事务使用流程概述

简单使用流程

TransactionAttribute txAttr; // 获取事务属性。

PlatformTransactionManager txManager; // 获取事务管理器,依赖 txAttr。

TransactionStatus status = txManager.getTransaction(txAttr); // 开启事务,得到事务状态。依赖 txManager 和 txAttr。事务状态 status 可能被封装到 TransactionInfo 中。

//执行业务逻辑

txManager.commit(status)/txManager.(status); // 提交或回退事务

简单执行流程

  1. 外部调用 @Transactional注解修饰的方法。
  2. org.springframework.transaction.interceptor.TransactionInterceptor#invoke 事务拦截器拦截方法。
  3. org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 事务处理的主要逻辑。
  4. 事务前置处理
    1. 获取数据库连接
    2. 创建事务
    3. 事务同步
  5. invocation.proceedWithInvocation() 执行业务逻辑
  6. 事务后置处理
    1. 提交或者回退事务
    2. 释放数据库连接
    3. 事务同步

事务属性关键实现类

RuleBasedTransactionAttribute -> DefaultTransactionAttribute -> DefaultTransactionDefinition,TransactionAttribute -> TransactionDefinition

JdbcTransactionManager -> AbstractPlatformTransactionManager -> DataSourceTransactionManager -> PlatformTransactionManager -> TransactionManager

DefaultTransactionStatus -> AbstractTransactionStatus -> TransactionStatus -> TransactionExecution,SavepointManager

TransactionAspectSupport.TransactionInfo 存储了事务的所有信息。

事务的数据库连接使用流程

DataSourceTransactionObject txObject = new DataSourceTransactionObject();

Connection newCon = obtainDataSource().getConnection();

txObject.setConnectionHolder(new ConnectionHolder(newCon), true);

txObject.getConnectionHolder().setSynchronizedWithTransaction(true); // 标识连接资源跟事务同步

txObject.getConnectionHolder().setTransactionActive(true); // 标识激活事务

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());

TransactionSynchronizationManager.setActualTransactionActive(true); // 真正激活事务

TransactionSynchronizationManager.initSynchronization(); // 初始化同步行为

数据库连接关键实现类

DataSourceTransactionManager.DataSourceTransactionObject -> JdbcTransactionObjectSupport -> SavepointManager,SmartTransactionObject

ConnectionHolder -> ResourceHolderSupport -> ResourceHolder

AbstractPlatformTransactionManager#transactionSynchronization = SYNCHRONIZATION_ALWAYS; // 始终激活事务同步,即使是空事务。

TransactionSynchronizationManager#actualTransactionActive // 标识当前是否有一个实际的事务处于活动状态,即示当前线程是否与一个实际的事务相关联。

事务流程详情

核心代码摘录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 仅保留 @Transactional 方法实际使用逻辑,省略其它逻辑。
// org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                         final InvocationCallback invocation) throws Throwable {

    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    final TransactionManager tm = determineTransactionManager(txAttr);
    
    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

    Object retVal;
    try {
        // This is an around advice: Invoke the next interceptor in the chain.
        // This will normally result in a target object being invoked.
        retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
        // target invocation exception
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }
    finally {
        cleanupTransactionInfo(txInfo);
    }
    commitTransactionAfterReturning(txInfo);
    return retVal;
}

主流程

入口方法

  1. org.springframework.transaction.interceptor.TransactionInterceptor#invoke
  2. org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

流程

  1. org.springframework.transaction.interceptor.TransactionAspectSupport#getTransactionAttributeSource 获取事务属性处理器,自动配置的实现是 AnnotationTransactionAttributeSource。
  2. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 解析 @Transactional 注解获取事务属性。首先从方法找注解,其次从方法所在的类上找,最后从接口或者父类上找。此处限制仅支持 public 方法。
    1. 首先从缓存 AbstractFallbackTransactionAttributeSource#attributeCache 查询。
    2. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute 查找 @Transactional 注解。此处限制仅支持 public 方法。
    3. 底层调用 org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 解析 @Transactional 注解,填充属性。
  3. org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager 获取对应的事务管理器。
    1. 主逻辑如下:
    2. 首先将 @Transactional 注解的 qualifier 属性作为事务管理器 bean name 查找;
    3. 其次将 TransactionAspectSupport#transactionManagerBeanName (默认未配置,为 null)作为事务管理器 bean name 查找;
    4. 然后使用默认管理器 TransactionAspectSupport#transactionManager(默认未配置,为 null);
    5. 最后从 bean factory 中查找 TransactionManager.class 类型的实现类作为默认事务管理器;
    6. 获取后会存入缓存 TransactionAspectSupport#transactionManagerCache,后续将直接从缓存中查找;默认事务管理器在缓存中的 key 为 DEFAULT_TRANSACTION_MANAGER_KEY = new Object()
  4. org.springframework.transaction.interceptor.TransactionAspectSupport#asPlatformTransactionManager 强转PlatformTransactionManager
  5. org.springframework.transaction.interceptor.TransactionAspectSupport#methodIdentification(java.lang.reflect.Method, java.lang.Class, org.springframework.transaction.interceptor.TransactionAttribute) 获取切点名称(类名+方法名),后续将作为事务名称。
  6. org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 创建事务,返回 TransactionInfo。方法 invokeWithinTransaction 并未直接使用 TransactionStatus 传递事务信息,而是封装为 TransactionInfo,该类记录了更多事务相关信息。
    1. 如果未主动指定事务名称,则使用 joinpointIdentification(类名称+方法名)。
    2. org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction 创建事务,如果 TransactionAttribute 与 PlatformTransactionManager 不为空。为空则是非法事务。
    3. org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo 封装事务相关信息为 TransactionInfo,并绑定到当前线程。
  7. invocation.proceedWithInvocation() 执行业务逻辑
  8. org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 业务逻辑执行抛出异常后的处理逻辑。
  9. org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo 清除线程中的事务信息
    1. org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#restoreThreadLocalStatus 重置 TransactionAspectSupport#transactionInfoHolder 状态。
    2. transactionInfoHolder.set(this.oldTransactionInfo); 恢复 oldTransactionInfo 与当前线程的绑定。
  10. org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning 业务逻辑执行成功后的处理逻辑,提交事务。
    1. 调用txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());提交事务。
    2. org.springframework.transaction.support.AbstractPlatformTransactionManager#commit 提交事务。
    3. 如果当前事务仅允许 rollback(defStatus.isLocalRollbackOnly())),则调用 processRollback 回退事务。org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback。
    4. 如果全局事务标识为仅允许 rollback,且本地事务非必须 commit,则调用 processRollback 回滚事务。
    5. org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit 处理提交事务。
  11. 返回结果,执行 return retVal;

分支 AbstractPlatformTransactionManager#processCommit

org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

功能

处理提交事务。

流程

  1. org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareForCommit 当前为空。
  2. org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerBeforeCommit 如果 status.isNewSynchronization(),触发 beforeCommit 回调逻辑。
    1. org.springframework.transaction.support.TransactionSynchronizationUtils#triggerBeforeCommit
    2. for-each TransactionSynchronizationManager.getSynchronizations() 调用 TransactionSynchronization#beforeCommit 方法。
    3. MyBatis 当前有 1 个实现,JdbcTemplate 无实现。
    4. org.mybatis.spring.SqlSessionUtils.SqlSessionSynchronization#beforeCommit
      1. 在事务提交之前(在“beforeCompletion”之前)被调用。此回调并不意味着事务将真正被提交。即使此方法已被调用,仍可能发生回滚。主要作用诸如将 SQL 语句刷新到数据库中等。
      2. 底层调用 org.apache.ibatis.session.defaults.DefaultSqlSession#commit, org.apache.ibatis.executor.BaseExecutor#commit。
      3. 底层最终调用 org.mybatis.spring.transaction.SpringManagedTransaction#commit,此处忽略 commit,执行空逻辑,因此未提交事务。
  3. org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerBeforeCompletion 如果 status.isNewSynchronization(),触发 beforeCompletion 回调逻辑。
    1. org.springframework.transaction.support.TransactionSynchronizationUtils#triggerBeforeCompletion
    2. for-each TransactionSynchronizationManager.getSynchronizations()) 调用 TransactionSynchronization#beforeCompletion 方法。
    3. MyBatis 当前有 1 个实现,JdbcTemplate 无实现。
    4. org.mybatis.spring.SqlSessionUtils.SqlSessionSynchronization#beforeCompletion 如果 session 无引用,则将 DefaultSqlSessionFactory-SqlSessionHolder 从当前线程解绑。
      1. org.springframework.transaction.support.TransactionSynchronizationManager#unbindResource 将 DefaultSqlSessionFactory-SqlSessionHolder 从当前线程解绑。
      2. org.apache.ibatis.session.defaults.DefaultSqlSession#close 关闭连接。
      3. 底层调用了 org.apache.ibatis.executor.BaseExecutor#close,org.springframework.jdbc.datasource.DataSourceUtils#doReleaseConnection。
      4. 最终调用 org.springframework.jdbc.datasource.ConnectionHolder#released,ConnectionHolder#currentConnection 置为空。
      5. 某些情况下会调用 Connection#close 方法,Spring 应当不涉及,忽略分析。
      6. org.apache.ibatis.session.defaults.DefaultSqlSession#closeCursors 关闭游标。
  4. 释放 Savepoint,如果存在。应该是处理嵌套事务的。
  5. 实际提交,如果是新事务。调用 org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit。
    1. 获取数据库连接,txObject.getConnectionHolder().getConnection()
    2. 数据库连接提交事务,con.commit(),具体逻辑由数据源定义。当前使用 Hikari 线程池数据源,具体调用 com.zaxxer.hikari.pool.ProxyConnection#commit 方法。
    3. ProxyConnection#commit中调用delegate.commit()实际提交事务。当前使用 H2 内置数据库,delegate 是 H2 数据库的 JDBC 实现。底层调用了 com.zaxxer.hikari.pool.ProxyConnection#commit,org.h2.jdbc.JdbcConnection#commit。
  6. org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCommit 如果 status.isNewSynchronization(),触发 afterCommit 回调逻辑。
    1. org.springframework.transaction.support.TransactionSynchronizationUtils#triggerAfterCommit
    2. MyBatis 当前有 1 个实现,JdbcTemplate 无实现。
    3. org.springframework.transaction.support.TransactionSynchronizationAdapter#afterCommit 空实现。
  7. org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCompletion 如果 status.isNewSynchronization(),触发 afterCompletion 回调逻辑。
    1. org.springframework.transaction.support.TransactionSynchronizationUtils#invokeAfterCompletion
    2. MyBatis 当前有 1 个实现,JdbcTemplate 无实现。
    3. org.mybatis.spring.SqlSessionUtils.SqlSessionSynchronization#afterCompletion 后置清理,如果 SqlSessionHolder 仍然活跃,SqlSessionSynchronization#holderActive 为true,则解绑 SqlSessionFactory-SqlSessionHolder,调用 SqlSession#close 关闭连接。
  8. org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion 清空变量,释放连接等等。
    1. TransactionSynchronizationManager.clear()清空 TransactionSynchronizationManager 持有的信息。
    2. org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion调用 TransactionSynchronizationManager.unbindResource解绑 DataSource-ConnectionHolder 与当前线程的绑定。
    3. org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction(java.sql.Connection, java.lang.Integer, boolean) 重置 Connection,恢复隔离基本、只读等属性。
    4. org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection 释放 Connection。
      1. org.springframework.jdbc.datasource.DataSourceUtils#doReleaseConnection
      2. org.springframework.jdbc.datasource.DataSourceUtils#doCloseConnection
      3. 当前使用 Hikari 线程池数据源,最终底层调用 com.zaxxer.hikari.pool.ProxyConnection#close。
    5. org.springframework.jdbc.datasource.ConnectionHolder#clear 清空 ConnectionHolder 持有的信息。
    6. 如果当前存在挂起的资源,status.getSuspendedResources(),则进行恢复,调用 org.springframework.transaction.support.AbstractPlatformTransactionManager#resume。主要恢复了 TransactionSynchronizationManager 中持有的信息。

补充知识

回调逻辑(同步行为)

有序调用

  1. beforeCommit
  2. beforeCompletion
  3. afterCommit
  4. afterCompletion

JdbcTemplate 无上述 4 种回调。

MyBatis 上述 4 种回调各有 1 个实现。

SqlSessionHolder#referenceCount

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

finally 和 catch 中均会调用 org.mybatis.spring.SqlSessionUtils#closeSqlSession,释放 SqlSessionHolder 中 referenceCount 的变量(即数值减一)。

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)

org.mybatis.spring.SqlSessionUtils#registerSessionHolder

org.springframework.transaction.support.ResourceHolderSupport#requested,请求 SqlSessionHolder 中 referenceCount 的变量(即数值加一)。

封装信息

事务信息主要封装在 TransactionInfo txInfo

数据库连接主要封装在 ConnectionHolder conHolder

事务信息关联数据库连接主要封装在 DataSourceTransactionObject txObject

其它 DefaultTransactionStatus status

重要分支

待补充分支

  1. 分支org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 业务逻辑执行抛出异常后的处理逻辑。
  2. 分支 org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback 处理回滚逻辑。
  3. 分支 org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 如果当前线程已存在事务,后续处理逻辑。

分支 AbstractPlatformTransactionManager#getTransaction

功能

创建事务

主流程

  1. org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction 获取事务。
    1. new DataSourceTransactionObject 主要封装了数据库连接信息。
    2. org.springframework.jdbc.datasource.DataSourceTransactionManager#obtainDataSource 获取数据源。
    3. org.springframework.transaction.support.TransactionSynchronizationManager#getResource 获取 Resource,key 是 DataSource,具体是 HikariDataSource。如果是第一次进入事务,该事务未开启数据库连接,则返回空。
    4. txObject.setConnectionHolder(conHolder, false) 如果是第一次进入事务,则 conHolder 为空。
  2. org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction 判断释放已存在事务。
    1. 条件是 txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive()
    2. 如果是第一次进入事务,则为 false。
  3. org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 如果当前已存在事务,处理逻辑。
  4. org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction 实际创建事务。
    1. org.springframework.transaction.support.AbstractPlatformTransactionManager#newTransactionStatus 创建 DefaultTransactionStatus,执行 new DefaultTransactionStatus
    2. org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
    3. org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareSynchronization 创建 TransactionStatus,准备 Synchronization。
  5. 如果当前线程不存在事务,且事务传播规则是指定值,则调用 org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareSynchronization 初始化事务同步 transaction synchronization。
    1. 传播规则指定值:PROPAGATION_NEVER,PROPAGATION_NOT_SUPPORTED,PROPAGATION_SUPPORTS。
    2. 创建 TransactionStatus,准备 Synchronization。

分支 DataSourceTransactionManager#doBegin

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

流程

  1. 如果 txObject 的实例变量 ConnectionHolder 为空(第一次进入事务),或已完成同步(txObject.getConnectionHolder().isSynchronizedWithTransaction())。
    1. org.springframework.jdbc.datasource.DataSourceTransactionManager#obtainDataSource 获取数据源。
    2. com.zaxxer.hikari.HikariDataSource#getConnection() 获取连接。当前使用的是 HikariDataSource。
    3. txObject.setConnectionHolder(new ConnectionHolder(newCon), true);填充 ConnectionHolder。
  2. txObject.getConnectionHolder().setSynchronizedWithTransaction(true)。标识资源已同步(resource,当前是指数据库连接)。
  3. org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction 根据事务属性 definition 配置数据库连接的隔离级别。
  4. 为数据库连接配置其它属性,例如只读等等。当前事务事务,关闭自动提交。
  5. txObject.getConnectionHolder().setTransactionActive(true);。标识事务已激活。
  6. 如果是新的 ConnectionHolder,则绑定 DataSource-ConnectionHolder 到当前线程,当前 DataSource 实际使用 HikariDataSource。调用 org.springframework.transaction.support.TransactionSynchronizationManager#bindResource。

分支 TransactionSynchronizationManager#bindResource

org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

流程

  1. org.springframework.transaction.support.TransactionSynchronizationUtils#unwrapResourceIfNecessary 获取 actualKey,如果是代理类,返回原始对象。
  2. 如果该 key 存在旧的值。
    1. 如果旧值是 ResourceHolder 且无效(ResourceHolder#isVoid 为 true),则忽略旧值。
    2. 否则抛出异常。
  3. 将新的值存储到 TransactionSynchronizationManager#resources 中。

分支 TransactionSynchronizationManager#getResource

  1. org.springframework.transaction.support.TransactionSynchronizationUtils#unwrapResourceIfNecessary 获取 actualKey,如果是代理类,返回原始对象。
  2. org.springframework.transaction.support.TransactionSynchronizationManager#doGetResource 根据 key 获取当前线程绑定的资源。
    1. 根据 key 从 TransactionSynchronizationManager#resources 中查询当前线程绑定的资源。
    2. 如果值是 ResourceHolder 且无效(ResourceHolder#isVoid 为 true)则清除该对象,并返回 null。
    3. 否则返回找到的值。

分支 TransactionSynchronizationUtils#unwrapResourceIfNecessary

org.springframework.transaction.support.TransactionSynchronizationUtils#unwrapResourceIfNecessary

功能

获取 actualKey,如果是代理类,返回原始对象。

流程

  1. 特殊处理代理对象,如果 key 是 InfrastructureProxy 或 ScopedObject 实现类,则获取 target 原始对象。
  2. 否则直接返回原始对象。

分支 TransactionAspectSupport#prepareTransactionInfo

功能

封装事务相关信息为 TransactionInfo,并绑定到当前线程。

主流程

  1. 将关键事务信息封装为 TransactionInfo,执行 new TransactionInfo
  2. org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#newTransactionStatus 将 TransactionStatus 封装到 TransactionInfo 中。
  3. org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#bindToThread 绑定 TransactionInfo 到当前线程,并存储旧的 oldTransactionInfo,线程变量的持有者是 TransactionAspectSupport#transactionInfoHolder

关键类变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo
protected static final class TransactionInfo {

    @Nullable
    private final PlatformTransactionManager transactionManager;

    @Nullable
    private final TransactionAttribute transactionAttribute;

    private final String joinpointIdentification;

    @Nullable
    private TransactionStatus transactionStatus;

    @Nullable
    private TransactionInfo oldTransactionInfo;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// org.springframework.jdbc.datasource.DataSourceTransactionManager.DataSourceTransactionObject
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {

    private boolean newConnectionHolder;

    private boolean mustRestoreAutoCommit;
}

// org.springframework.jdbc.datasource.JdbcTransactionObjectSupport
public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {
    @Nullable
    private ConnectionHolder connectionHolder;

    @Nullable
    private Integer previousIsolationLevel;

    private boolean readOnly = false;

    private boolean savepointAllowed = false;
}    
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// org.springframework.jdbc.datasource.ConnectionHolder
public class ConnectionHolder extends ResourceHolderSupport {
	@Nullable
	private ConnectionHandle connectionHandle;

	@Nullable
	private Connection currentConnection;

	private boolean transactionActive = false;

	@Nullable
	private Boolean savepointsSupported;

	private int savepointCounter = 0;
}

// org.springframework.transaction.support.ResourceHolderSupport
public abstract class ResourceHolderSupport implements ResourceHolder {
    // Mark the resource as synchronized with a transaction.
	private boolean synchronizedWithTransaction = false;

	private boolean rollbackOnly = false;

    // Set the timeout for this object in milliseconds.
	@Nullable
	private Date deadline;

    // holder 被使用次数。
	private int referenceCount = 0;

    // holder 是否被视为“无效”的
	private boolean isVoid = false;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// org.springframework.transaction.interceptor.TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {}

// org.springframework.transaction.interceptor.TransactionAspectSupport
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
	private static final Object DEFAULT_TRANSACTION_MANAGER_KEY = new Object();
    
	private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
			new NamedThreadLocal<>("Current aspect-driven transaction");
}

绑定到当前线程的资源

  1. TransactionInfo
    1. org.springframework.transaction.interceptor.TransactionAspectSupport#transactionInfoHolder
    2. private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");
    3. 绑定时机 org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo
    4. 解绑或恢复挂起信息的时机 org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo
  2. 资源
    1. org.springframework.transaction.support.TransactionSynchronizationManager#resources
    2. private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
    3. 解绑或恢复挂起信息的时机 AbstractPlatformTransactionManager#cleanupAfterCompletion
  3. 同步
    1. org.springframework.transaction.support.TransactionSynchronizationManager#synchronizations
    2. private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
    3. 解绑或恢复挂起信息的时机 AbstractPlatformTransactionManager#cleanupAfterCompletion
  4. TransactionSynchronizationManager 中的事务标识信息
    1. private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name");
    2. private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status");
    3. private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level");
    4. private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active");
    5. 解绑或恢复挂起信息的时机 AbstractPlatformTransactionManager#cleanupAfterCompletion

关键类描述

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource {}

// org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
public abstract class AbstractFallbackTransactionAttributeSource
		implements TransactionAttributeSource, EmbeddedValueResolverAware {

	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {}
}

TransactionSynchronizationManager

org.springframework.transaction.support.TransactionSynchronizationManager

关键方法

TransactionSynchronizationManager#getResource

TransactionSynchronizationManager#doGetResource

TransactionSynchronizationManager#unbindResource

TransactionSynchronizationManager#doUnbindResource

事务判断

存在两种事务判断方法

  1. org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive
  2. org.springframework.transaction.support.TransactionSynchronizationManager#isSynchronization

isActualTransactionActive

功能:检查当前是否存在真实的事务(物理事务)

isSynchronizationActive

功能:检查当前是否启用了事务同步

对比维度isActualTransactionActiveisSynchronizationActive
检查对象检查真实事务是否存在检查事务同步是否激活
返回true条件存在物理事务事务同步已初始化(可能没有真实事务)
依赖关系通常isSynchronizationActive为true时才会检查不依赖事务是否存在
典型场景判断是否在事务中执行判断是否可以注册同步回调

物理事务是指在数据库层面实际开启的事务,具有ACID特性。当Spring说"存在物理事务"时,意味着:

  1. 数据库连接已设置非自动提交。connection.setAutoCommit(false) 已被执行。
  2. 数据库已分配事务ID。数据库服务器内部已创建事务上下文(如MySQL的tx_id
  3. 资源已被绑定。JDBC Connection/Hibernate Session等资源已与当前线程绑定。
****物理事务(Physical Transaction)逻辑事务(Logical Transaction)
****层级数据库层面真实存在Spring抽象的事务概念
开启时机仅当传播行为需要新事务时创建所有@Transactional
方法都会进入逻辑事务
资源消耗占用数据库连接和事务ID仅内存中的标记
示例场景PROPAGATION_REQUIRED
新建事务时
PROPAGATION_SUPPORTS
无物理事务时

isSynchronizationActive 为 true,isActualTransactionActive 为 false 的场景

  1. 当方法使用 @Transactional(propagation = Propagation.SUPPORTS),且调用方无事务时。
  2. 手动初始化同步但未启动实际事务。
  3. 事务资源准备阶段,在事务管理器开始事务但尚未完成资源绑定时(短暂状态)。
  4. 其它。

事务关联

MyBatis 关联 Spring 事务

阶段1

org.apache.ibatis.executor.loader.ResultLoader#selectList

org.apache.ibatis.executor.loader.ResultLoader#newExecutor

environment.getTransactionFactory()

transactionFactory.newTransaction(

org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

org.apache.ibatis.executor.BaseExecutor#transaction 记录了 SpringManagedTransactionFactory 创建的事务,其中包含数据源。

阶段2

org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)

org.apache.ibatis.executor.BaseExecutor#queryFromDatabase

org.apache.ibatis.executor.SimpleExecutor#doQuery

org.apache.ibatis.executor.SimpleExecutor#prepareStatement

org.apache.ibatis.executor.BaseExecutor#getConnection

transaction.getConnection()

org.mybatis.spring.transaction.SpringManagedTransaction#getConnection

org.mybatis.spring.transaction.SpringManagedTransaction#openConnection

org.springframework.jdbc.datasource.DataSourceUtils#getConnection

org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

TransactionSynchronizationManager.getResource(dataSource)

JdbcTemplate 关联 Spring 事务

END