1)、就是将多个数据源全部注入到bean中,根据需要实现多数据源之间的切换。
2)、使用baomidou的@DS注解。见文章@DS注解实现数据源动态切换
com.baomidou
dynamic-datasource-spring-boot-starter
3.5.1
##设置默认的数据源或者数据源组,默认值即为master
spring.datasource.dynamic.primary=master
#设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
spring.datasource.dynamic.strict=false
postgresql 配置 主库的配置
spring.datasource.dynamic.datasource.master.url = jdbc:postgresql://localhost:5432/zhejiang_data_repository
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=root
spring.datasource.dynamic.datasource.master.driver-class-name=org.postgresql.Driver
#从库的配置
spring.datasource.dynamic.datasource.slave.url = jdbc:postgresql://localhost:5432/server_test_logdb
spring.datasource.dynamic.datasource.slave.username=postgres
spring.datasource.dynamic.datasource.slave.password=123456
spring.datasource.dynamic.datasource.slave.driver-class-name=org.postgresql.Driver
使用@DS(“slave”)注解在类或者方法,同时使用方式上优先类上
1.配置文件配置多个数据库连接
#主库
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
2.注入数据源
将配置的数据源全部注入到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;
}
}
或
@Configuration
public class DataSourceConfig {
/* - 数据源1配置
*/
@Bean(“ds1”)
@ConfigurationProperties(“spring.datasource.ds1”)
public DataSource ds1() {
return DataSourceBuilder.create().build();
}
/**
- 数据源2配置
*/
@Bean(“ds2”)
@ConfigurationProperties(“spring.datasource.ds2”)
public DataSource ds2() {
return DataSourceBuilder.create().build();
}
/**
- 动态数据源配置
*/
@Bean
@Primary
public DataSource dynamicDataSource(@Qualifier(“ds1”) DataSource ds1, @Qualifier(“ds2”) DataSource ds2) {
DynamicDataSource ds = new DynamicDataSource();
// 设置数据源映射关系
ds.setTargetDataSources(Map.of(
“ds1”, ds1,
“ds2”, ds2
));
// 设置默认数据源
ds.setDefaultTargetDataSource(ds1);
return ds;
}
}
- 主库数据源bean名称
3.实现数据源动态切换
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;
}
}
4.切换数据源管理类
/**
-
数据源切换工具
-
@author yjj
-
@version 1.0
-
@since 2022 -08-29 09:54:05
/
public class DataSourceUtil {
/*- 数据源属于一个公共的资源
- 采用ThreadLocal可以保证在多线程情况下线程隔离
*/
private static final ThreadLocal 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();
}
}
5.添加自定义注解Db,标注在方法上,指定方法内部执行时所使用的数据源
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Db {
String value();
}
6.现切面类DynamicDataSourceAspect,对所有标注了Db注解的方法进行增强
@Aspect
@Component
public class DynamicDataSourceAspect {
/**
* Mapper方法切面实现,对所有标注了Db注解的方法生效
*/
@Around(“@annotation(byx.test.Db)”)
public Object around(ProceedingJoinPoint jp) throws Throwable {
// 获取方法上的Db注解
MethodSignature methodSignature = (MethodSignature) jp.getSignature();
Method method = methodSignature.getMethod();
Db db = method.getAnnotation(Db.class);
try {// 方法执行前先设置当前数据源,再执行方法DataSourceHolder.setDataSource(db.value());return jp.proceed();} finally {// 方法结束后清理当前数据源DataSourceHolder.clear();}
}
}
7.使用方法
@Mapper
public interface UserMapper {
@Select(“SELECT * FROM users”)
@Db(“ds1”)
List listUsersFromDs1();
@Select("SELECT * FROM users")
@Db("ds2")
List<User> listUsersFromDs2();
}