一、实现
- 1、配置多数据源切换及事务管理器(dataSource和marsDataSource两个数据源配置略)
@Configuration
public class MultipleDataSource extends AbstractRoutingDataSource {
private static final Logger logger = LoggerFactory.getLogger(MultipleDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
logger.info("当前数据源:{}", DataSourceTypeManager.get());
return DataSourceTypeManager.get();
}
@Bean
public MultipleDataSource dynamicDataSource(
@Qualifier("dataSource") DataSource dataSource,
@Qualifier("marsDataSource") DataSource marsDataSource) {
MultipleDataSource dynamicDataSource = new MultipleDataSource();
Map<Object, Object> map = new HashMap<>();
System.out.println(dataSource.getClass());
map.put(DataSourceTypeManager.BOP, dataSource);
map.put(DataSourceTypeManager.MARS, marsDataSource);
dynamicDataSource.setTargetDataSources(map);
dynamicDataSource.setDefaultTargetDataSource(dataSource);
return dynamicDataSource;
}
@Bean
@Primary
public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dynamicDataSource);
return dataSourceTransactionManager;
}
public class DataSourceTypeManager {
public static final String MARS = "mars";
public static final String BOP = "bop";
private static final ThreadLocal<String> dataSourceKey = new ThreadLocal<String>(){
};
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
public static String get(){
return dataSourceKey.get();
}
public static void set(String dataSourceType){
dataSourceKey.set(dataSourceType);
}
public static void cleanDataSource(){
dataSourceKey.remove();
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MarsSelect {
}
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(com.xxx.MarsSelect)")
public void switchDataSource(JoinPoint point) {
DataSourceTypeManager.setDataSourceKey(DataSourceTypeManager.MARS);
}
@After("@annotation(com.xxx.MarsSelect)")
public void afterSwitchDataSource(JoinPoint point) {
DataSourceTypeManager.setDataSourceKey(DataSourceTypeManager.BOP);
}
}
二、注意点
- 1、 配置的DataSourceTransactionManager引用的DataSource需要是实现AbstractRoutingDataSource的bean(以下称dynamicDataSource),而不是配在dynamicDataSource中的targetDataSources的任意一个(没找到原因,知道的大神麻烦告诉我下),否则事务不生效。
- 2、不管是采用xml配置还是@Transactional注解开启事务,都需要在调用这个开启事务的方法之前完成数据源切换(如果要切换到非默认数据源时),否则这个非默认数据源会不生效。