欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > SpringBoot + Druid + Dynamic Datasource 多数据源配置

SpringBoot + Druid + Dynamic Datasource 多数据源配置

2025/5/13 4:37:44 来源:https://blog.csdn.net/baidu_25117757/article/details/147860428  浏览:    关键词:SpringBoot + Druid + Dynamic Datasource 多数据源配置

SpringBoot + Druid + Dynamic Datasource 多数据源配置

  • 1、依赖
  • 2、application.yml
  • 3、多数据源 Duid 自动装配详解
    • 3.1、自动装配 spring.datasource.dynamic
    • 3.2、自动装配多数据源 datasource
    • 3.3、自动装配每个数据源下的 duid 配置
    • 3.4、自动装配 StatViewServlet
    • 3.5、自动装配 WebStatFilter
    • 3.6、自动装配 AopPatterns
    • 3.7、Filter 配置类
  • 4、Druid 监控页面
    • 4.1、首页
    • 4.2、数据源列表
    • 4.2、SQL 监控
    • 4.3、SQL 防火墙
    • 4.4、Web 应用
    • 4.5、URI 监控
    • 4.6、Web Session 监控
    • 4.7、Spring 监控
    • 4.8、JSON API
  • 5、动态切换数据源
    • 5.1、数据源枚举
    • 5.2、Controller 层
    • 5.3、AOP 根据入参自动切换数据源
  • 6、日志输出效果

1、依赖

<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>4.3.1</version><exclusions><exclusion><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.24<</version></dependency>

2、application.yml

特别注意:多数据源 druid 要配置到每一个数据源里面

spring:application:name: DynamicDatasourcedatasource:druid:stat-view-servlet:enabled: trueallow:deny:reset-enable: falselogin-username: adminlogin-password: 123456url-pattern: /druid/*web-stat-filter:enabled: true#对这些请求放行exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"#拦截该项目下的一切请求url-pattern: /*session-stat-enable: trueprincipal-session-name: session_nameprincipal-cookie-name: cookie_nameprofile-enable: true# 包匹配,表示匹配以com.github.wxhnyfy.dynamicdatasource开头的包名,多个用逗号隔开aop-patterns: com.github.wxhnyfy.dynamicdatasource.*dynamic:primary: master # 设置默认的数据源或者数据源组,默认值即为 masterdatasource:master:#设置默认的数据源driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/region?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8username: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource# druid连接池设置druid:# 配置初始化线程数initialSize: 5# 最小线程数minIdle: 5# CPU核数+1,也可以大些但不要超过20,数据库加锁时连接过多性能下降maxActive: 11# 最大等待时间,内网:800,外网:1200(三次握手1s)maxWait: 60000# 连接可空闲存活时间(ms)timeBetweenEvictionRunsMillis: 60000# 连接保持空闲而不被驱逐的最长存活时间(ms)minEvictableIdleTimeMillis: 300000# 用来检测连接是否有效的sql,如果validationQuery为空,那么testOnBorrow、testOnReturn、testWhileIdle这三个参数都不会起作用validationQuery: SELECT 1# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效;testWhileIdle: true# 建议配置为false,申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。testOnBorrow: false# 建议配置为false,归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能;testOnReturn: false# PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭poolPreparedStatements: false# 保持minIdle数量的长连接keepAlive: true# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。# 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。缺省值为-1# 开启poolPreparedStatments后生效maxPoolPreparedStatementPerConnectionSize: 20# 是否合并多个DruidDataSource的监控数据useGlobalDataSourceStat: true# 配置监控统计拦截的filtersfilters: stat,wall,slf4jstat:logSlowSql: trueslowSqlMillis: 2000mergeSql: truedbType: mysqlwall:# 可配置项参考类:com.alibaba.druid.wall.WallConfigmulti-statement-allow: truealter-table-allow: falsedrop-table-allow: falseslf4j:# 只有当 isStatementExecutableSqlLogEnable() isStatementLogEnabled() 都为ture的情况才打印 可执行sql# 在{# LogFilter#logExecutableSql }使用statement-executable-sql-log-enable: true# 在{# LogFilter#logExecutableSql }使用statement-log-enabled: truestatement-create-after-log-enabled: falsestatement-log-error-enabled: trueresult-set-log-enabled: false#statementPrepareAfterLogEnable# 准备好的sql语句打印(此时为执行前)未进行参数拼接statement-prepare-after-log-enabled: false#isStatementParameterSetLogEnabled#打印参数statement-parameter-set-log-enabled: false#statementExecuteAfterLogEnable#sql语句执行完成后打印(执行后)未进行参数拼接statement-execute-after-log-enabled: false#statementCloseAfterLogEnablestatement-close-after-log-enabled: false#不打印清除参数日志statement-parameter-clear-log-enable: false# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=2000slave:url: jdbc:mysql://localhost:3307/region?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource# druid连接池设置druid:# 配置初始化线程数initialSize: 5# 最小线程数minIdle: 5# CPU核数+1,也可以大些但不要超过20,数据库加锁时连接过多性能下降maxActive: 11# 最大等待时间,内网:800,外网:1200(三次握手1s)maxWait: 60000# 连接可空闲存活时间(ms)timeBetweenEvictionRunsMillis: 60000# 连接保持空闲而不被驱逐的最长存活时间(ms)minEvictableIdleTimeMillis: 300000# 用来检测连接是否有效的sql,如果validationQuery为空,那么testOnBorrow、testOnReturn、testWhileIdle这三个参数都不会起作用validationQuery: SELECT 1# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效;testWhileIdle: true# 建议配置为false,申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。testOnBorrow: false# 建议配置为false,归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能;testOnReturn: false# PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭poolPreparedStatements: false# 保持minIdle数量的长连接keepAlive: true# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。# 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。缺省值为-1# 开启poolPreparedStatments后生效maxPoolPreparedStatementPerConnectionSize: 20# 是否合并多个DruidDataSource的监控数据useGlobalDataSourceStat: true# 配置监控统计拦截的filtersfilters: stat,wall,slf4jstat:logSlowSql: trueslowSqlMillis: 2000mergeSql: truedbType: mysqlwall:# 可配置项参考类:com.alibaba.druid.wall.WallConfigmulti-statement-allow: truealter-table-allow: falsedrop-table-allow: falseslf4j:# 只有当 isStatementExecutableSqlLogEnable() isStatementLogEnabled() 都为ture的情况才打印 可执行sql# 在{# LogFilter#logExecutableSql }使用statement-executable-sql-log-enable: true# 在{# LogFilter#logExecutableSql }使用statement-log-enabled: truestatement-create-after-log-enabled: falsestatement-log-error-enabled: trueresult-set-log-enabled: false#statementPrepareAfterLogEnable# 准备好的sql语句打印(此时为执行前)未进行参数拼接statement-prepare-after-log-enabled: false#isStatementParameterSetLogEnabled#打印参数statement-parameter-set-log-enabled: false#statementExecuteAfterLogEnable#sql语句执行完成后打印(执行后)未进行参数拼接statement-execute-after-log-enabled: false#statementCloseAfterLogEnablestatement-close-after-log-enabled: false#不打印清除参数日志statement-parameter-clear-log-enable: false# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=2000

3、多数据源 Duid 自动装配详解

3.1、自动装配 spring.datasource.dynamic

由于我们引入了 dynamic-datasource-spring-boot-starter,启动时会优先自动装配 com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration,并且在类 com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure 之前装配
在这里插入图片描述
在这里插入图片描述
会自动装配以下属性,参考类 com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties,datasource 就是我们配置的多数据源

在这里插入图片描述
在这里插入图片描述

3.2、自动装配多数据源 datasource

参考类 com.baomidou.dynamic.datasource.creator.DataSourceProperty
在这里插入图片描述

3.3、自动装配每个数据源下的 duid 配置

这个配置和 Druid 的层级稍有一些不同
参考类 com.baomidou.dynamic.datasource.creator.druid.DruidConfig
在这里插入图片描述
在这里插入图片描述

数据源的 Filter 配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4、自动装配 StatViewServlet

参考类:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidStatViewServletConfiguration
在这里插入图片描述
在这里插入图片描述

3.5、自动装配 WebStatFilter

参考类:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidWebStatFilterConfiguration
在这里插入图片描述
在这里插入图片描述

3.6、自动装配 AopPatterns

参考类:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidSpringAopConfiguration
在这里插入图片描述

在这里插入图片描述

3.7、Filter 配置类

  • wall: com.alibaba.druid.wall.WallConfig
  • slf4j、log4j、log4j2、commonsLog: 四个日志 filter 只有实现不同,配置类都是同一个,com.alibaba.druid.filter.logging.LogFilter
  • stat:com.alibaba.druid.filter.stat.StatFilter

日志 Filter 要引入对应的依赖,Druid 的 LoggerName 在类 com.alibaba.druid.filter.logging LogFilter,配置日志打印级别时需要使用下面的 LoggerName
在这里插入图片描述

4、Druid 监控页面

4.1、首页

访问地址:http://IP:端口/上下文/druid/index.html
在这里插入图片描述

4.2、数据源列表

要看每一个数据源的 filter 类名,看一下是否和启用的 Filter 一致,再看一起其他的配置是否能正常读取
在这里插入图片描述

4.2、SQL 监控

执行过 SQL 后,Druid 能对 SQL 进行监控,但是不能区分是哪个数据源执行的。由于我们开启了SQL合并,所以看到的SQL都会带有占位符
在这里插入图片描述
点击去能看到每条SQL的执行详情。
在这里插入图片描述

4.3、SQL 防火墙

能对黑白名单进行统计,但是不能区分是哪个数据源执行的
在这里插入图片描述
示例,我们在 spring.datasource.dynamic.datasource.master.wall 配置了不能执行 select 语句
在这里插入图片描述
SQL 会执行报错
在这里插入图片描述
能正常监控到黑名单 SQL
在这里插入图片描述

4.4、Web 应用

在这里插入图片描述

4.5、URI 监控

能监控到执行SQL的请求
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6、Web Session 监控

在这里插入图片描述

在这里插入图片描述

4.7、Spring 监控

根据 aop-pattern 配置包名进行监控
在这里插入图片描述
在这里插入图片描述

4.8、JSON API

把各个页面的信息转为 JSON 数据
在这里插入图片描述
在这里插入图片描述

5、动态切换数据源

这里给出一个参考解决方案

5.1、数据源枚举

public enum DataSourceEnum {MASTER("master"),SLAVE("slave");private String value;DataSourceEnum(String value) {this.value = value;}public String getValue() {return value;}
}

5.2、Controller 层

在 Controller 的每个方法入参都加上数据源枚举

@ApiOperation(value = "执行自定义SQL")
@ApiImplicitParams({@ApiImplicitParam(name = "envCode", value = "数据源标识", required = true, paramType = "query", example = "MASTER", dataTypeClass = DataSourceEnum.class),@ApiImplicitParam(name = "query", value = "查询字符串", required = true, paramType = "query", example = "select * from chinapostoffice limit 100", dataTypeClass = String.class),
})
@GetMapping("/getChinaPostOffice ")
public Response<JSONArray> getChinaPostOffice(@RequestParam DataSourceEnum envCode,@RequestParam String query
) {logger.info(">>> query: {}", query);List<Map<String, Object>> list = customMapper.selectList(query);logger.info(">>> 总共 {} 条数据", list.size());logger.info(">>> 数据: {}", JSONArray.from(list, JSONWriter.Feature.WriteMapNullValue).toJSONString(JSONWriter.Feature.WriteMapNullValue));return new Response<JSONArray>().success(JSONArray.from(list, JSONWriter.Feature.WriteMapNullValue));
}

5.3、AOP 根据入参自动切换数据源

DynamicDataSourceContextHolder 实现原理,可参考源码,解析得很详细了
在这里插入图片描述

@Aspect
@Component
// 确保在事务切面之前执行
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AutoSwitchDataSourceAop {private static final Logger logger = LoggerFactory.getLogger(AutoSwitchDataSourceAop.class);/*** 当前指定的默认数据源*/@Value("${spring.datasource.dynamic.primary}")private String dynamicPrimaryDataSource;/*** 定义匹配需要切换数据源的方法的切点* 匹配com.github.wxhnyfy.dynamicdatasource.controller包、com.github.wxhnyfy.dynamicdatasource.impl.service包下所有包含DataSourceEnum参数的方法* 支持DataSourceEnum参数在任意参数位置(不限于第一个参数)** @param joinPoint 切点* @return 目标执行方法* @throws Throwable 异常*/@Around("execution(* com.github.wxhnyfy.dynamicdatasource.controller.*.*(com.github.wxhnyfy.dynamicdatasource.enums.DataSourceEnum, ..)) " +"|| execution(* com.github.wxhnyfy.dynamicdatasource.impl.service.*.*(com.github.wxhnyfy.dynamicdatasource.enums.DataSourceEnum, ..))")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();String methodName = signature.getMethod().getName();logger.info("进入 SwitchDataSourceAspect 的方法名: {}", methodName);logger.debug("当前指定的默认数据源:{}", dynamicPrimaryDataSource);DataSourceEnum envCode = null;try {// 获取方法参数中的EnvCode值envCode = extractEnvCode(joinPoint);// 切换数据源if (envCode != null) {logger.info("数据库环境标识:{}", envCode);String previousDs = DynamicDataSourceContextHolder.peek();logger.info("方法 [{}] 切换数据源: {} -> {}", methodName, previousDs, envCode.getValue());DynamicDataSourceContextHolder.push(envCode.getValue());}// 执行目标方法return joinPoint.proceed();} finally {// 清理数据源(恢复到默认数据源)if (envCode != null) {DynamicDataSourceContextHolder.clear();}}}/*** 通过反射获取方法参数* 自动识别DataSourceEnum类型的参数* 支持任意位置的DataSourceEnum参数** @param joinPoint 切点* @return DataSourceEnum参数*/private DataSourceEnum extractEnvCode(ProceedingJoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Parameter[] parameters = signature.getMethod().getParameters();// 遍历参数查找EnvCode类型的参数for (int i = 0; i < parameters.length; i++) {if (parameters[i].getType().isAssignableFrom(DataSourceEnum.class)) {Object arg = joinPoint.getArgs()[i];if (arg instanceof DataSourceEnum) {return (DataSourceEnum) arg;}}}return null;}
}

6、日志输出效果

Mybatis-Plus 我们使用 org.apache.ibatis.logging.slf4j.Slf4jImpl 日志实现,配置对应的日志级别

mybatis-plus:mapper-locations: classpath:mapper/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
logging:level:root: info# 注意,logback不支持**匹配com.github.wxhnyfy.**.mapper: debugdruid.sql.Statement: debug

日志输出效果如下图
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词