前言
大多数 Spring 应用程序只有一个数据源,只需要一个事务管理器(TransactionManager)。
但是在多个数据源的情况下,我们就需要在一个应用程序中配置多个独立的事务管理器。
我们可以通过 @Transactional 的 value 或 transactionManager 属性来指定让哪个 TransactionManager 生效。
那么,一个数据源 与 多数据源的事物管理配置有什么不同呢?
正文
事物管理相关的几个核心概念有:DataSource、TransactionManager 和 TransactionInterceptor。
- DataSource
DataSource 是用来获取 DB 连接的。 - TransactionManager
用来管理事物,核心的接口有 PlatformTransactionManager,它可以获取连接、提交/回滚事物。 - TransactionInterceptor
它是 spring-tx 用来实现声明式事物管理的核心类,它会对事物方法进行拦截,然后实现事物的操作(提交/回滚事物)。
所以,我们在进行 spring 的事物管理配置的时候,这三个重要的角色都需要参与进来:DataSource、TransactionManager 和 TransactionInterceptor。
单个数据源的事物管理配置
可能你会说 Spring 开启事物管理不就是使用一个 @EnableTransactionManagement
就搞定了吗?确实也是这样。
仔细想想,我们不禁会有疑问:
1、@EnableTransactionManagement
能开启事物管理的原理是什么呢?
2、如果没有 @EnableTransactionManagement
,我们自己配置事物管理的话,应当如何配置呢?
手动进行事物管理配置
我们先来看一下,如果没有使用 @EnableTransactionManagement
的情况下,应该如何来进行事物管理的配置?
如果使用 MyBatis 来操作数据库的话,手动进行事物管理的配置可以分为四个步骤进行:
- 1、定义数据源 DataSource
- 2、定义基于 DataSource 的 TransactionManager(事物管理器)
- 3、定义 Advisor 来拦截 @Transactional 方法(主要是让 Advice:TransactionInterceptor 生效)
- 4、定义基于 DataSource 的 SqlSessionFactory(通过 MyBatis 来操作 sql)
例如:
@Configuration
@MapperScan(basePackages = "com.kvn.mapper.biz", sqlSessionFactoryRef = "bizSqlSessionFactory")
public class MasterMybatisConfig {
@Bean("biz")
@ConfigurationProperties(prefix = "spring.datasource.biz")
public DataSource bizDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 创建 biz 数据源的事物管理器
*/
@Bean(name = "bizTxManager")
public PlatformTransactionManager bizTxManager(@Qualifier("biz") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("bizSqlSessionFactory")
public SqlSessionFactory bizSqlSessionFactory(@Qualifier("biz") DataSource dataSource) throws Exception {
// 设置数据源
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
//mapper的xml文件位置
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String locationPattern = "classpath*:/mapper/biz/*.xml";
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
//对应数据库的entity位置
String typeAliasesPackage = "com.kvn.entity.biz";
sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
return sqlSessionFactoryBean.getObject();
}
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
TransactionAttributeSource transactionAttributeSource = new AnnotationTransactionAttributeSource();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
// 定义 Advisor --> Pointcut + Advice
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource); // 供 Pointcut 使用
advisor.setAdvice(interceptor); // Advice
return advisor;
}
}
注意:如果我们不需要对数据源进行事物管理的话,可以不配置 transactionAdvisor
@EnableTransactionManagement
开启事物管理的原理
在一个只有一个数据源的 SpringBoot 工程中,我们只需要配置一个 @EnableTransactionManagement
就能开启事物管理,让 @Transactional
生效,这是为什么呢?
使用 @EnableTransactionManagement
之后,SpringBoot 为我们配置哪些 bean 来支持事物管理呢?
@EnableTransactionManagement 的作用
查看 @EnableTransactionManagement 的源码,我们可以发现它帮我们注册了 BeanFactoryTransactionAttributeSourceAdvisor
,也就是让 TransactionInterceptor
来拦截 @Transactional 标记的方法
但是 @EnableTransactionManagement
并没有帮我们注册 TransactionManager
和 DataSource
。
那么,TransactionManager
和 DataSource
是如何自动注册的呢?
SpringBoot 会帮我们默认注册一个 HikariDataSource
:
当只有一个 DataSource 时,SpringBoot 会默认帮我们注册一个 TransactionManager
:
可以看到,如果我们的工程中只有一个数据源的话,SpringBoot 就会帮我们自动注册一个 TransactionManager
和 HikariDataSource
@EnableTransactionManagement 的作用是负责注册必要的 Spring 组件,比如:
BeanFactoryTransactionAttributeSourceAdvisor
和TransactionInterceptor
,这些组件为注释驱动的事务管理提供了动力和支持。
- BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisor 实现了PointcutAdvisor
接口,它持有的 Pointcut 决定了匹配 @Transactional 注解标记的方法;
它持有的 Advice,即TransactionInterceptor
,实现了具体的事物拦截逻辑。- TransactionInterceptor
TransactionInterceptor 在做事物方法拦截时,会去决定使用哪个 TransactionManager,即TransactionAspectSupport.determineTransactionManager()
方法实现的功能。
多个数据源的事物管理配置
从上面对单个数据源的事物管理配置的研究,我们可以发现 @EnableTransactionManagement
的作用就是帮我们自动注册 BeanFactoryTransactionAttributeSourceAdvisor
来支持对 @Transactoinal
方法的拦截。
而 TransactionManager
和 DataSource
是需要另外进行配置的。当工程中只有一个数据源的情况下,SpringBoot 又会默认帮我们注册 TransactionManager
和 DataSource
,所以,在只有一个数据源的情况下,我们通过 @EnableTransactionManagement
注解就能顺利的通过 spring-tx 来管理事物。
当工程中有多个数据源的时候(>=2),我们依然可以通过 @EnableTransactionManagement
来自动注册 BeanFactoryTransactionAttributeSourceAdvisor
,但是 SpringBoot 就不会自动注册 TransactionManager
和 DataSource
了,而需要我们手动进行配置。
所以,配置 n 个数据源的事物管理的步骤如下:
1、通过 @EnableTransactionManagement
来开启对 @Transactional
方法的拦截
2、定义 n 个数据源 DataSource
3、定义基于 DataSource 的 TransactionManager(事物管理器)
4、定义基于 DataSource 的 SqlSessionFactory (通过 MyBatis 操作 sql)
手动配置 2 个数据源的例子:
- 定义 master 数据源 & 事物管理器
- 定义 slave 数据源 & 事物管理器
- 数据源的 properties 配置
注意:多数据源的情况下,需要使用类似
@Transactional("masterTxManager")
来指定事物方法使用的事物管理器是哪个。
小结
配置 spring 的事物管理,大体分为三个步骤:(单数据源 与 多数据源 都是如此)
- 1、定义数据源 DataSource
- 2、定义基于 DataSource 的 TransactionManager(事物管理器)
- 3、定义 Advisor 来拦截 @Transactional 方法(主要是让 Advice:TransactionInterceptor 生效)
不管是一个数据源,还是多个数据源,都是上面的套路。
一个数据源的配置 与 多个数据源的配置 的不同是:如果工程中只需要一个数据源,那么 SpringBoot 可以为我们做到全自动的配置,只需要使用 @EnableTransactionManagement
就可以使用 spring 的事物管理。
SpringBoot 能自动配置单个数据源的事物管理的原理是:
1、spring-boot-autoconfigure.jar
中的 DataSourcePoolMetadataProvidersConfiguration
类会帮我们自动注册 HikariDataSource
2、spring-boot-autoconfigure.jar
中的 DataSourceTransactionManagerAutoConfiguration
类会帮我们自动注册 TransactionManager
3、@EnableTransactionManagement
会注册 Advisor: BeanFactoryTransactionAttributeSourceAdvisor
如果是多数据源进行事物管理配置的话,步骤如下:
- 1、手动定义 n 个 DataSource
- 2、手动定义基于 DataSource 的 TransactionManager(事物管理器)
- 3、添加
@EnableTransactionManagement
来开启对 @Transactional 方法的拦截
系统的学习源码知识,请点击视频讲解:
SpringIoC源码由浅入深 : https://edu.51cto.com/course/30243.html