多数据源配置思路
- yml中配置多个数据源;
- 通过AOP自动切换不同的数据源;
- 配合Mybatis-plus使用
yml配置
spring:
datasource:
druid:
db1:
url: jdbc:mysql://10.168.1.118:3306/rd?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#初始连接数 默认0
initial-size: 10
#最大连接数,默认8
max-active: 30
#最小闲置数
min-idle: 10
#获取连接的最大等待时间,单位毫秒
max-wait: 2000
db2:
url: jdbc:postgresql://127.0.0.1:5432/postgres
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
#初始连接数 默认0
initial-size: 10
#最大连接数,默认8
max-active: 30
#最小闲置数
min-idle: 10
#获取连接的最大等待时间,单位毫秒
max-wait: 2000
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL
mapper-locations: classpath:mappers/**/*.xml
启动多个数据源
@EnableTransactionManagement
@Configuration
@MapperScan("com.kuiper.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* mysql数据源
*
* @return
*/
@Bean("db1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1")
public DataSource db1DataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* postgresql数据源
*
* @return
*/
@Bean("db2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2")
public DataSource db2DataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* @description: 动态数据源配置
* @param: db1DataSource mysql数据源,db2DataSource postgresql数据源
* @return:
* @author czl
* @date: 2021/6/16 11:02
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("db1DataSource") DataSource db1DataSource, @Qualifier("db2DataSource") DataSource db2DataSource) {
/** 创建动态数据源决策者 */
DynamicDataSource dynamicDataSource = new DynamicDataSource();
/** 存放多个数据源 */
Map<Object, Object> targerDataSource = new HashMap<>(16);
targerDataSource.put(DataSourceTypeEnum.db1DataSource.getValue(), db1DataSource);
targerDataSource.put(DataSourceTypeEnum.db2DataSource.getValue(), db2DataSource);
/** 讲多个数据源注入targetDataSources */
dynamicDataSource.setTargetDataSources(targerDataSource);
/** 默认数据源 */
dynamicDataSource.setDefaultTargetDataSource(db1DataSource);
return dynamicDataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
/** 创建mybatis中的sqlSessionFactoryBean工厂 */
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
/** 向sqlSessionFactoryBean工厂中注入数据源 */
sqlSessionFactory.setDataSource(this.multipleDataSource(db1DataSource(), db2DataSource()));
/** 创建MybatisConfiguration */
MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
mybatisConfiguration.setJdbcTypeForNull(JdbcType.NULL);
/** 开启驼峰命名规则 */
mybatisConfiguration.setMapUnderscoreToCamelCase(true);
/** 是否开启缓存 */
mybatisConfiguration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(mybatisConfiguration);
return sqlSessionFactory.getObject();
}
}
枚举DataSourceTypeEnum类
public enum DataSourceTypeEnum {
/**
* mysql数据源源
*/
db1DataSource("db1DataSource"),
/**
* postgresql数据源
*/
db2DataSource("db2DataSource");
private String value;
DataSourceTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
动态决策数据源
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* @description: 动态数据源决策
* @param: null
* @return:
* @author
* @date: 2021/6/16 11:09
*/
@Override
protected Object determineCurrentLookupKey() {
String dataSourceType = DataSourceContextHolder.getDataSourceType();
log.info("当前数据源为:{}", dataSourceType);
return dataSourceType;
}
}
设置、添加、获取数据源
public class DataSourceContextHolder {
private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 设置数据源
*
* @param dataSourceTypeEnum
*/
public static void setDataSourceType(DataSourceTypeEnum dataSourceTypeEnum) {
CONTEXT_HOLDER.set(dataSourceTypeEnum.getValue());
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDataSourceType() {
return (String) CONTEXT_HOLDER.get();
}
/**
* 清除上下文数据
*
* @return
*/
public static void clearDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
AOP实现动态数据源的切换
@Component
@Order(-100)
@Slf4j
@Aspect
public class DataSourceAspect {
@Pointcut("execution(* com.kuiper.mapper.db1..*.*(..))")
private void db1Aspect() {
}
@Pointcut("execution(* com.kuiper.mapper.db2..*.*(..))")
private void db2Aspect() {
}
@Before("db1Aspect()")
public void db1DataSource() {
log.info("切换数据源为:{}", DataSourceTypeEnum.db1DataSource.getValue());
DataSourceContextHolder.setDataSourceType(DataSourceTypeEnum.db1DataSource);
}
@Before("db2Aspect()")
public void db2DataSource() {
log.info("切换数据源为:{}", DataSourceTypeEnum.db2DataSource.getValue());
DataSourceContextHolder.setDataSourceType(DataSourceTypeEnum.db2DataSource);
}
}
项目工程结构
跨域请求配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
/** 设置允许跨域路径 */
registry.addMapping("/**")
/** 设置允许跨域请求的域名 */
.allowedOriginPatterns("*")
/** 是否允许证书 不在默认开启 */
.allowCredentials(true)
/** 设置允许的方法 */
.allowedMethods("*")
/** 跨域允许时间 */
.maxAge(3600);
}
}