現(xiàn)象 :
當(dāng)一個Spring Boot 項目在配置了多個數(shù)據(jù)源 , 在編寫Service層方法的時候 , 直接在service方法的上添加的@Transactional直接實現(xiàn)事務(wù)管理的方式是失效的 .
原因 :
以最近接觸到的一個持久層框架使用的是Jpa的項目為例 , 該項目通過硬編碼(配置類)的方式 , 在項目中配置了兩個不同的數(shù)據(jù)源 , 所以這個項目分別根據(jù)兩個數(shù)據(jù)源配置了各自的事務(wù)管理器PlatformTransactionManager , 如下 :
第一個數(shù)據(jù)源的事務(wù)管理器配置類 :
@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());
}
}
第二個數(shù)據(jù)源事務(wù)管理器配置類 :
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryTwo", //實體管理
transactionManagerRef = "transactionManagerTwo", //事務(wù)管理
basePackages = {"com.xxx"} //數(shù)據(jù)源所應(yīng)用到的包
)
public class WeeklyDataSourceConfig {
@Autowired
@Qualifier("weeklyDataSource")
private DataSource weeklyDataSource;
//這里省略部分配置 ...
@Primary
@Bean(name = "transactionManagerTwo")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject());
}
}
可以看到第二個事務(wù)管理器的Bean方法上添加了@Primary注解 , 所以在通過PlatformTransactionManager類型注入事務(wù)管理器的bean時 , 默認(rèn)是根據(jù)類型去注入 , 如果該類型有多個Bean , 如不通過bean的名字去注入 , 則默認(rèn)是會注入被@Primary標(biāo)識的bean的 ;
所以在這個項目中 , 當(dāng)在業(yè)務(wù)層方法添加@Transactional注解時 , 默認(rèn)是調(diào)用了transactionManagerTwo這個bean , 而我在編寫service層的方法時 , 調(diào)用的是第一個數(shù)據(jù)源對應(yīng)的Dao層方法 , 所以直接添加@Transactional是不能實現(xiàn)事務(wù)管理的 ,
解決辦法 :
需要在使用@Transactional注解時指定使用的事務(wù)管理器的bean的名字 , 比如我這里調(diào)用的是第一個數(shù)據(jù)源的dao層方法 , 所以需要指定對應(yīng)的事務(wù)管理器 : @Transactional(transactionManager = "transactionManagerOne") .
@Transactional(transactionManager = "transactionManagerOne")
public void deleteById(Integer Id) {
//...
}