现象 :
当一个Spring Boot 项目在配置了多个数据源 , 在编写Service层方法的时候 , 直接在service方法的上添加的@Transactional
直接实现事务管理的方式是失效的 .
原因 :
以最近接触到的一个持久层框架使用的是Jpa的项目为例 , 该项目通过硬编码(配置类)的方式 , 在项目中配置了两个不同的数据源 , 所以这个项目分别根据两个数据源配置了各自的事务管理器PlatformTransactionManager
, 如下 :
第一个数据源的事务管理器配置类 :
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryOne",
transactionManagerRef = "transactionManagerOne",
basePackages = {"com.xxx.xxx"}
)
public class OneDataSourceConfig {
@Autowired
@Qualifier("oneDataSource")
private DataSource oneDataSource;
// .. 这里省略部分bean配置
@Bean(name = "transactionManagerOne")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject());
}
}
第二个数据源事务管理器配置类 :
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryTwo", //实体管理
transactionManagerRef = "transactionManagerTwo", //事务管理
basePackages = {"com.xxx"} //数据源所应用到的包
)
public class WeeklyDataSourceConfig {
@Autowired
@Qualifier("weeklyDataSource")
private DataSource weeklyDataSource;
//这里省略部分配置 ...
@Primary
@Bean(name = "transactionManagerTwo")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject());
}
}
可以看到第二个事务管理器的Bean方法上添加了@Primary
注解 , 所以在通过PlatformTransactionManager
类型注入事务管理器的bean时 , 默认是根据类型去注入 , 如果该类型有多个Bean
, 如不通过bean的名字去注入 , 则默认是会注入被@Primary
标识的bean的 ;
所以在这个项目中 , 当在业务层方法添加@Transactional
注解时 , 默认是调用了transactionManagerTwo
这个bean , 而我在编写service层的方法时 , 调用的是第一个数据源对应的Dao层方法 , 所以直接添加@Transactional
是不能实现事务管理的 ,
解决办法 :
需要在使用@Transactional
注解时指定使用的事务管理器的bean的名字 , 比如我这里调用的是第一个数据源的dao层方法 , 所以需要指定对应的事务管理器 : @Transactional(transactionManager = "transactionManagerOne")
.
@Transactional(transactionManager = "transactionManagerOne")
public void deleteById(Integer Id) {
//...
}