测试库为ORACLE数据库,其实都一样 ,参考地址: https://www.cnblogs.com/lhat/p/11970554.html
测试源码 : 链接:https://pan.baidu.com/s/1b6UJaGi73868djLjdhWUjQ 提取码:zsq6
1.配置文件,重点在于配置三个数据库连接
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#默认数据源
spring.datasource.default-datasource.url=jdbc:oracle:thin:@localhost:1521:orcl
spring.datasource.default-datasource.username=ZHANG
spring.datasource.default-datasource.password=Zhenghe123
spring.datasource.default-datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#多数据源
#数据源1
spring.datasource.target-datasources.datasource1.url=jdbc:oracle:thin:@localhost:1521:orcl
spring.datasource.target-datasources.datasource1.username=ZHANG
spring.datasource.target-datasources.datasource1.password=Zhenghe123
spring.datasource.target-datasources.datasource1.driver-class-name=oracle.jdbc.driver.OracleDriver
#数据源2
spring.datasource.target-datasources.datasource2.url=jdbc:oracle:thin:@localhost:1521:orcl
spring.datasource.target-datasources.datasource2.username=SHENG
spring.datasource.target-datasources.datasource2.password=Zhenghe123
spring.datasource.target-datasources.datasource2.driver-class-name=oracle.jdbc.driver.OracleDriver
# 初始连接数
spring.datasource.druid.initial-size=10
# 最大连接池数量
spring.datasource.druid.max-active=100
# 最小连接池数量
spring.datasource.druid.min-idle=10
# 配置获取连接等待超时的时间
spring.datasource.druid.max-wait=60000
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.druid.min-evictable-idle-time-millis=300000
#spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
#spring.datasource.druid.test-while-idle=true
#spring.datasource.druid.test-on-borrow=false
#spring.datasource.druid.test-on-return=false
#===mybatis 配置===
# 注意:一定要对应mapper映射xml文件的所在路径
mybatis.mapper-locations=classpath*:mapper/*.xml
# Mybatis SQL语句控制台打印
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启驼峰命名 譬如数据库create_time 自动映射pojo属性createTime
mybatis.configuration.map-underscore-to-camel-case=true
2.排除不自动扫数据源配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.zhang.oracledb.mapper")
public class OracledbApplication {
public static void main(String[] args) {
SpringApplication.run(OracledbApplication.class, args);
}
}
3.创建枚举类,作为数据源的key
public enum DataSourceType {
/** 默认数据源key */
DEFAULT_DATASOURCE,
/** 数据源1key*/
DATASOURCE1,
/** 数据源2key*/
DATASOURCE2,
}
4.核心配置,实例化所有数据源
@Configuration
public class DataSourceConfig {
@Bean //读取默认数据源,并实例化
@ConfigurationProperties(prefix = "spring.datasource.default-datasource")
public DataSource defaultDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean //读取数据源1,并实例化
@ConfigurationProperties(prefix = "spring.datasource.target-datasources.datasource1")
public DataSource dataSource1() {
return DruidDataSourceBuilder.create().build();
}
@Bean //读取数据源2,并实例化
@ConfigurationProperties(prefix = "spring.datasource.target-datasources.datasource2")
public DataSource dataSource2() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource dynamicDataSource(DataSource defaultDataSource, DataSource dataSource1, DataSource dataSource2) {
// 注意:该方法的参数名称要和前面前面三个datasource对象在Spring容器中的bean名称一样
// 或者使用 @Qualifier 指定具体的bean
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.DEFAULT_DATASOURCE.name(), defaultDataSource);
targetDataSources.put(DataSourceType.DATASOURCE1.name(), dataSource1);
targetDataSources.put(DataSourceType.DATASOURCE2.name(), dataSource2);
return new DynamicDataSource(defaultDataSource, targetDataSources);
}
}
5.新建 DynamicDataSource类继承 AbstractRoutingDataSource ,添加构造方法把所有数据源加入和重写 determineCurrentLookupKey方法
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
//获取数据源的核心方法, 通过key获取数据源
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
6.核心方法详解
7.使用本地线程变量,控制数据源切换
/**
* 本地线程类,获取切换移除数据源
**/
public class DataSourceContextHolder {
public static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>();
public static void setDataSourceType(String dsType) {
CONTEXT_HOLDER.set(dsType);
}
public static String getDataSourceType() {
return CONTEXT_HOLDER.get();
}
public static void removeDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
8.测试
@GetMapping("/test1")
public List<Map<String, Object>> test(String dataSourceIndex) {
// 根据参数值的不同,切换数据源
if ("1".equals(dataSourceIndex)) {
//获取数据源1
DataSourceContextHolder.setDataSourceType(DataSourceType.DATASOURCE1.name());
} else if ("2".equals(dataSourceIndex)) {
//获取数据源2
DataSourceContextHolder.setDataSourceType(DataSourceType.DATASOURCE2.name());
}
List<Map<String, Object>> mapList = testMapper.selectList();
// 清除线程内部变量数据源key ,此步一定不能少
DataSourceContextHolder.removeDataSourceType();
return null;
}