以后方便查看,故做一下笔记。也是参考网上朋友的内容,但时间比较久远不知道是那一篇,请谅解。
主要用得的是spring提供的AbstractRoutingDataSource类来实现数据源动态切换。
同时使用aop技术来实现在需要的地方声明使用哪种数据源即可。
- 继承AbstractRoutingDataSource
@Slf4j
public class DynamicDatasource extends AbstractRoutingDataSource {
private static class DynamicDataSourceHolder {
private static final DynamicDatasource instance = new DynamicDatasource();
}
public static final DynamicDatasource getInstance() {
return DynamicDataSourceHolder.instance;
}
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceKey();
}
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
super.setTargetDataSources(targetDataSources);
DATASOURCE_MAP.putAll(targetDataSources);
super.afterPropertiesSet();// 必须添加该句,否则新添加数据源无法识别到
}
}
- 使用ThreadLocal保存当前线程的datasource情况:
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static synchronized void setDataSourceKey(String key) {
contextHolder.set(key);
}
public static String getDataSourceKey() {
return contextHolder.get();
}
public static void clearDataSourceKey() {
contextHolder.remove();
}
}
- 为mybatis注入多数据源配置
@Configuration
@MapperScan(basePackages = {"com.mappers"}, sqlSessionFactoryRef = "sqlSessionFactory")
public class JdbcConfig {
@Value("${mybatis-plus.type-aliases-package}")
private String typeAliasesPackage;
@Value("${mybatis-plus.mapper-locations}")
private String mapperLocation;
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
@ConfigurationProperties(prefix = "hive.datasource")
public DataSource hiveDataSource() {
return new DruidDataSource();
}
@Bean(name = "impalaDataSource")
@ConfigurationProperties(prefix = "impala.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
public DynamicDatasource dynamicDatasource() {
DynamicDatasource dynamicDatasource = DynamicDatasource.getInstance();
Map<Object, Object> datasourceMap = new HashMap<>();
datasourceMap.put("datasource", dataSource());
datasourceMap.put("impala", impalaDataSource());
datasourceMap.put("hive", hiveDataSource());
dynamicDatasource.setTargetDataSources(datasourceMap);
dynamicDatasource.setDefaultTargetDataSource(dataSource());
return dynamicDatasource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
PathMatchingResourcePatternResolver pathResolver = new PathMatchingResourcePatternResolver();
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource());
sqlSessionFactory.setMapperLocations(pathResolver.getResources(mapperLocation));
sqlSessionFactory.setTypeAliasesPackage(typeAliasesPackage);
return sqlSessionFactory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
- aop方式实现动态切换
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Ds {
String value() default "datasource";
}
@Component
@Aspect
@Slf4j
public class DynamicDataSourceAspect {
@Before("@annotation(com.annotation.Ds)")
public void before(JoinPoint joinPoint) {
Ds dsAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Ds.class);
log.info("Switch datasource to [{}] in method [{}]", dsAnnotation.value(), joinPoint.getSignature());
DynamicDataSourceContextHolder.setDataSourceKey(dsAnnotation.value());
}
@After("@annotation(com.annotation.Ds)")
public void after(JoinPoint joinPoint) {
log.info("Reset datasource to [{}] in method [{}]", DynamicDataSourceContextHolder.getDataSourceKey(), joinPoint.getSignature());
DynamicDataSourceContextHolder.clearDataSourceKey();
}
}
5.使用
只需要在需要使用指定事务的方法上使用@Ds进行申明即可。名称为指定数据源Map中的key。
网友评论