由于工作需要,要求能在普通spring数据源和shardingSphere数据源之间的动态切换。默认走shardingSphere数据源,由shardingSphere进行读写分离、分布式事物、数据分片等管理。然后可以根据某个动态标识,走普通spring数据源。实现如下:
1、首选创建两种类型的数据源
1)普通数据源
/**
* 非ShardingSphere托管的数据源
* @return slaveDataSource
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
2)定义shardingSphere数据源,这里是使用YamlShardingSphereDataSourceFactory工厂类,从nacos读取sharding-jdbc.yml配置,进行数据源创建
/**
* ShardingSphere托管的数据源
* @return shardingDataSource
*/
@Bean
public DataSource dataSource(){
ConfigService configService = nacosConfigManager.getConfigService();
try {
String shardingConfig = configService.getConfig("sharding-jdbc.yml", "DEFAULT_GROUP", 1000);
return YamlShardingSphereDataSourceFactory.createDataSource(shardingConfig.getBytes());
}catch (Exception e) {
e.printStackTrace();
}
}
3)定义动态路由数据源
@Bean
@Primary
public DataSource routingDataSource(@Qualifier("dataSource") DataSource shardingDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("shardingDataSource",shardingDataSource);
targetDataSources.put("slaveDataSource",slaveDataSource);
routingDataSource.setTargetDataSources(targetDataSources);
routingDataSource.setDefaultTargetDataSource(shardingDataSource);
return routingDataSource;
}
2、继承AbstractRoutingDataSource类,AbstractRoutingDataSource是Spring提供的一个抽象类,用于定义路由数据源的基本原理和实现方式,它有一个抽象的方法 determineCurrentLookupKey(),这个方法决定使用哪个数据源。
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
package com.demo;
/**
* 数据库动态路由上下文
*
* @author daily360
*/
public class DbContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDbType(String dbType) {
contextHolder.set(dbType);
}
public static String getDbType() {
return contextHolder.get();
}
public static void clearDbType() {
contextHolder.remove();
}
}
3、最后在自定义注解,根据实际业务需要传入相应的路由key,在切面类拦截注解并且将路由key赋给DbContextHolder。如下
@Ds(DsType.slaveDataSource)
@Override
public Map<String, Long> rangeStatistics(RequestParam param){
return service.rangeStatistics(param);
}