1、配置多数据源
# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 main: url: jdbc:mysql://ip:port/first username: root password: 123456 # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: true url: jdbc:mysql://ip:port/second username: root password: 123456 # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: test login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true
2、创建数据源枚举类
/** * 动态数据源枚举类 */ public enum DBTypeEnum { MAIN, SLAVE; private String value; DBTypeEnum(String value) { this.value = value; } public String getValue() { return value; } }
3、自定义注解,用于传递数据源
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
DBTypeEnum value() default DBTypeEnum.main;
}
4、创建动态数据源管理器 DbContextHolder,主要用来设置获取数据源
/**
* 动态数据源DbContextHolder管理器
*/
public class DbContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
/**
* 设置数据源
*
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
5、创建DynamicDataSource来动态获取数据源,主要实现数据源路由类AbstractRoutingDataSource
/**
* 它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
String datasource = DbContextHolder.getDbType();
return datasource;
}
}
6、配置DataSourceAspect,只要有注解的就根据参数切换数据源
/** * 多数据源处理 * * @author ruoyi */ @Aspect @Order(1) @Component public class DataSourceAspect { @Pointcut("@annotation(com.carbon.common.annotation.DataSource)" + "|| @within(com.carbon.common.annotation.DataSource)") public void dsPointCut() { } @Around("dsPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { DataSource dataSource = getDataSource(point); if (StringUtils.isNotNull(dataSource)) { DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); } try { return point.proceed(); } finally { // 销毁数据源 在执行方法之后 DynamicDataSourceContextHolder.clearDataSourceType(); } } /** * 获取需要切换的数据源 */ public DataSource getDataSource(ProceedingJoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); if (Objects.nonNull(dataSource)) { return dataSource; } return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); } }
最后只需要在需要切换数据源的方法上加上@DataSource注解即可