动态数据源切换
实际业务需求中,往往可能有一些业务需求需要连接多个库,这时就需要一个项目配置多个数据库的情况,本文讲解实现数据源的动态切换的其中一种方式。
1、就是将多个数据源全部注入到bean中,根据需要实现多数据源之间的切换。
2、使用baomidou的@DS注解。见文章
@DS注解实现数据源动态切换
- 配置文件配置多个数据库连接
#主库
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:postgresql://localhost:5432/sgeoc_sec_system
spring.datasource.username=postgres
spring.datasource.password=123456
spring.datasource.driver-class-name=org.postgresql.Driver
#从库
spring.slave-datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.slave-datasource.url=jdbc:postgresql://localhost:5432/server_test_system
spring.slave-datasource.username=postgres
spring.slave-datasource.password=123456
spring.slave-datasource.driver-class-name=org.postgresql.Driver
-
注入数据源
将配置的数据源全部注入到bean中,可以设置默认的数据源,也可以动态设置系统使用的数据源。
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据源注入
*
* @author yjj
* @version 1.0
* @since 2022 -08-29 09:50:30
*/
@Slf4j
@Configuration
public class DataSourceConfig {
/**
* 主库数据源bean名称
*/
public static final String MASTER_DATASOURCE = "masterDataSource";
/**
* 从库数据源bean名称
*/
public static final String SLAVE_DATASOURCE = "slaveDataSource";
/**
* 主库数据源对象bean生成
* @param properties 配置项
* @return DruidDataSource
*/
@Bean(MASTER_DATASOURCE)
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource masterDataSource(DataSourceProperties properties) {
DruidDataSource build = properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
log.info("配置主数据库:{}", build);
return build;
}
/**
* 从库数据源对象bean生成
* @param properties 配置项
* @return DruidDataSource
*/
@Bean(SLAVE_DATASOURCE)
@ConfigurationProperties(prefix = "spring.slave-datasource")
public DruidDataSource slaveDataSource(DataSourceProperties properties) {
DruidDataSource build = properties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
log.info("配置从数据库:{}", build);
return build;
}
/**
* 数据源配置
* @param masterDataSource 主库数据源对象
* @param slaveDataSource 从库数据源对象
* @return DataSource
* @Primary 优先使用这个DataSource对象bean
*/
@Bean
@Primary
@DependsOn(value = {MASTER_DATASOURCE, SLAVE_DATASOURCE})
public DataSource routingDataSource(@Qualifier(MASTER_DATASOURCE) DruidDataSource masterDataSource,
@Qualifier(SLAVE_DATASOURCE) DruidDataSource slaveDataSource) {
if (StringUtils.isBlank(slaveDataSource.getUrl())) {
log.info("没有配置从数据库,默认使用主数据库");
return masterDataSource;
}
Map<Object, Object> map = new HashMap<>();
map.put(DataSourceConfig.MASTER_DATASOURCE, masterDataSource);
map.put(DataSourceConfig.SLAVE_DATASOURCE, slaveDataSource);
DynamicDataSource routing = new DynamicDataSource();
//设置动态数据源
routing.setTargetDataSources(map);
//设置默认数据源
routing.setDefaultTargetDataSource(masterDataSource);
log.info("主从数据库配置完成");
return routing;
}
}
-
实现数据源动态切换
通过继承AbstractRoutingDataSource类,这个抽象类中有一个属性为【targetDataSources】,该属性为map结构,所有需要切换的数据源都存在这个map里面,根据指定的key获取对应的数据源,从而实现动态数据源的切换。则需要重写该抽象类中的【determineCurrentLookupKey】抽象方法,该方法的返回值决定了需要切换的数据源key,然后根据这个key去之前的【targetDataSources】Map中取数据源。
import com.southsmart.sso.util.DataSourceUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源
*
* @author yjj
* @version 1.0
* @since 2022 -08-29 09:55:26
*/
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String db = DataSourceUtil.getDb();
log.info("使用数据源:{}", db);
return db;
}
}
- 切换数据源管理类
/**
* 数据源切换工具
*
* @author yjj
* @version 1.0
* @since 2022 -08-29 09:54:05
*/
public class DataSourceUtil {
/**
* 数据源属于一个公共的资源
* 采用ThreadLocal可以保证在多线程情况下线程隔离
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
/**
* 设置数据源名
*
* @param dbType the db type
*/
public static void setDb(String dbType) {
contextHolder.set(dbType);
}
/**
* 获取数据源名
*
* @return db
*/
public static String getDb() {
return (contextHolder.get());
}
/**
* 清除数据源名
*/
public static void clearDb() {
contextHolder.remove();
}
}
- 使用
/**
* 默认使用主库
* 通过setDB()方法可以切换你想使用的数据源
*/
@PostMapping("loginTest")
public Result<String> test() {
//切换使用从库数据源
DataSourceUtil.setDb(DataSourceConfig.SLAVE_DATASOURCE);
return Result.ok();
}
版权声明:本文为weixin_45003796原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。