[TOC]
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave01")
@ConditionalOnProperty(prefix = "spring.datasource.slave01", name = "enabled", havingValue = "true")
public DataSource slave01DataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
//配置默认数据源
dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
//配置多数据源
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.getSourceName(), masterDataSource());
targetDataSources.put(DataSourceType.SLAVE01.getSourceName(), slave01DataSource());
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
}
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 主库数据源
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.100.60:3306/demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: root
# 从库数据源
slave01:
enabled: true
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.100.60:3306/demo01?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: root
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
@Slf4j
public class DataSourceContextHolder {
/**
* 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 设置数据源变量
* @param dataSourceType
*/
public static void setDataSourceType(String dataSourceType){
log.info("切换到{}数据源", dataSourceType);
CONTEXT_HOLDER.set(dataSourceType);
}
/**
* 获取数据源变量
* @return
*/
public static String getDataSourceType(){
return CONTEXT_HOLDER.get();
}
/**
* 清空数据源变量
*/
public static void clearDataSourceType(){
CONTEXT_HOLDER.remove();
}
}
public List<User> findAll() {
DataSourceContextHolder.setDataSourceType("slave01");
List<User> users = userDao.findAll();
DataSourceContextHolder.clearDataSourceType();
return users;
}
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
// 根据determineCurrentLookupKey函数返回map的key
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
// 如果找的到key对应的value则使用其他数据源,要不然使用默认的
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}