一、数据库连接信息配置
Spring Boot 的默认配置文件是 application.properties ,由于有两个数据库配置,因此添加配置文件 jbdc.properties ,添加以下自定义的主从数据库配置:
# master
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/master?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.master.username=root
spring.datasource.master.password=111111
# slave
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/slave?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.slave.username=root
spring.datasource.slave.password=111111
二、数据源配置
根据连接信息,把数据源注入到Spring中,添加DataSourceSupper文件,配置如下:
@Configuration
@PropertySource("classpath:config/jdbc.properties")
@Slf4j
public class DataSourceSupper implements ApplicationContextAware {
@Bean(initMethod = "init")
@ConfigurationProperties("spring.datasource.master")
public DruidDataSource dataSourceMaster() {
return DruidDataSourceBuilder.create().build();
}
@Bean(initMethod = "init")
@ConfigurationProperties("spring.datasource.slave")
public DruidDataSource dataSourceSlave() {
return DruidDataSourceBuilder.create().build();
}
@Autowired
ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Primary
@DependsOn()
@Bean
public AbstractRoutingDataSource dataSource() {
Map<String, DruidDataSource> beans = applicationContext.getBeansOfType(DruidDataSource.class);
DynamicDataSource proxy = new DynamicDataSource();
//设置默认数据源
proxy.setDefaultTargetDataSource(dataSourceMaster());
Map<Object, Object> targetDataSources = new HashMap<>(beans.size());
//查找全部数据源
List<String> source = new ArrayList<>();
for (Map.Entry<String, DruidDataSource> d : beans.entrySet()) {
String value = StringUtils.subString(d.getKey(), "dataSource", null).toLowerCase();
source.add(value);
targetDataSources.put(value, d.getValue());
}
proxy.setTargetDataSources(targetDataSources);
//刷新数据源
proxy.afterPropertiesSet();
log.info("数据源配置完毕,数据源个数:" + targetDataSources.size() + "(" + String.join(",", source) + ")");
return proxy;
}
注意:
此处使用 PropertySource 指定数据库配置文件,ConfigurationProperties 指定数据源配置前缀
实现ApplicationContextAware接口,可以拿到applicationContext,通过getBean取出所有数据源之后配置默认数据源。
使用 Map 保存多个数据源,并设置到动态数据源对象中,其中key我们做了处理,存入的是master和slave。
使用注解 Primary 优先从动态数据源中获取。
三、动态数据源设置
前面的配置已把多个数据源注入到 Spring 中,接着对动态数据源进行配置。
1、添加jdbc依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
2、添加动态数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDataSource();
}
}
注意:
继承抽象类 AbstractRoutingDataSource ,需要实现方法 determineCurrentLookupKey,即路由策略。
DatabaseContextHolder类是我们自定义的Threadlocal,可以通过改变Threadlocal从而动态切换数据源。
3、DatabaseContextHolder类配置
public class DatabaseContextHolder {
/**
* 使用ThreadLocal把数据源与当前线程绑定
*/
private static final ThreadLocal<String> dataSources = new ThreadLocal<>();
public static void setDataSource(String dataSourceName) {
dataSources.set(dataSourceName);
}
public static String getDataSource() {
return dataSources.get();
}
public static void clearDataSource() {
dataSources.remove();
}
}
四、动态数据源使用
DatabaseContextHolder.setDataSource("slave");
业务代码
业务代码
业务代码
DatabaseContextHolder.clearDataSource();
默认是使用master数据源查询,可通过setDataSource切换slave数据源,使用后要记得clearDataSource,防止Threadlocal内存泄露。
五、参考资料
1、https://juejin.cn/post/6844904050262016007