Spring Boot 2.x 项目在没有手动指定数据源时,默认使用 HikariCP。HikariCP 的优点是启动快、占用资源少,但它不提供图形化 SQL 监控和慢查询面板,排查线上 SQL 问题时通常要借助日志或 APM 工具。Druid 则把连接池、SQL 统计、防火墙和监控页面做成了一个整体,尤其适合业务开发阶段快速观察 SQL 执行次数、响应时间和慢查询分布。整合 Druid 的步骤可以拆成三块:切换数据源、补齐连接池参数、开启监控功能。真正容易出错的并不是核心配置本身,而是监控页面没有生效、驱动类名写错、wall 过滤器误拦截或者多数据源下手动构建 DataSource 时漏掉 filters。下面按完整流程和错误分类展开。

一、引入依赖并完成基础配置
使用官方提供的 druid-spring-boot-starter 是最省事的整合方式,它内部已经包含了 DruidDataSource 自动配置、StatFilter、WallFilter 以及监控 Servlet 的注册能力。需要先确认 Spring Boot 版本,Boot 2.x 可以使用较新的 1.2.x 版本,Boot 3.x 需要选择支持 jakarta.servlet 的 Druid 版本,建议使用 1.2.20 以上。依赖只需要一个,不必再单独引入 druid,否则可能出现重复的 druid 类冲突。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.23</version>
</dependency>
依赖加入后,如果项目里同时存在 HikariCP 的自动配置,通常可以通过 spring.datasource.type 显式指定为 DruidDataSource,避免加载顺序带来的不确定结果。基础连接信息和连接池参数可以放在 application.yml 或 application.properties 中。下面用 properties 格式给出一个最小可运行配置,MySQL 8 需要特别注意驱动类名和 URL 参数。
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username=root spring.datasource.password=123456 # 连接池初始化参数 spring.datasource.druid.initial-size=5 spring.datasource.druid.min-idle=5 spring.datasource.druid.max-active=20 spring.datasource.druid.max-wait=60000 spring.datasource.druid.time-between-eviction-runs-millis=60000 spring.datasource.druid.min-evictable-idle-time-millis=300000 spring.datasource.druid.validation-query=SELECT 1 spring.datasource.druid.test-while-idle=true spring.datasource.druid.test-on-borrow=false spring.datasource.druid.test-on-return=false
这段配置中,spring.datasource.type 的作用是告诉 Spring Boot 使用 Druid 作为 DataSource 实现,spring.datasource.druid 前缀下的参数由 Druid starter 进行绑定。initial-size、min-idle、max-active 控制连接池初始化数量和容量,validation-query 用来检测连接活性。test-while-idle=true 配合 time-between-eviction-runs-millis 可以在空闲回收线程中及时剔除失效连接,避免真正执行 SQL 时才发现连接已经断开。
二、开启监控页面与 SQL 统计
Druid 的监控页面由 StatViewServlet 提供,Web 请求统计由 WebStatFilter 提供。使用 starter 时不需要自己写 Servlet 注册代码,只需要打开对应配置项。StatViewServlet 默认关闭,所以很多人没有配置 enabled=true 就去访问 /druid 页面,结果必然是 404。
# 监控页 Servlet spring.datasource.druid.stat-view-servlet.enabled=true spring.datasource.druid.stat-view-servlet.url-pattern=/druid/* spring.datasource.druid.stat-view-servlet.login-username=admin spring.datasource.druid.stat-view-servlet.login-password=admin123 spring.datasource.druid.stat-view-servlet.allow=127.0.0.1 spring.datasource.druid.stat-view-servlet.deny=192.168.1.10 # Web 统计过滤器 spring.datasource.druid.web-stat-filter.enabled=true spring.datasource.druid.web-stat-filter.url-pattern=/* spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/* # SQL 统计 spring.datasource.druid.filter.stat.enabled=true spring.datasource.druid.filter.stat.slow-sql-millis=2000 spring.datasource.druid.filter.stat.log-slow-sql=true spring.datasource.druid.filter.stat.merge-sql=true
上面的配置中,stat-view-servlet.url-pattern 设置了监控页地址前缀,启动后访问 http://localhost:8080/druid/index.html 可以看到登录页。allow 表示白名单,deny 表示黑名单,两者都支持 IP 或 IP 段。即使在内网环境也不建议把 allow 留空后再关闭登录,否则只要知道端口和路径的人就能看到完整的 SQL 记录。
SQL 统计部分由 filter.stat 控制。slow-sql-millis 定义慢查询阈值,单位是毫秒;log-slow-sql 控制是否在日志中输出慢 SQL;merge-sql 可以把参数化后的 SQL 与真实参数合并展示。比如一条 SELECT * FROM user WHERE id = ? 在监控页中既能看模板,也能看到实际执行时 id 具体是多少,对开发调试非常有帮助。
如果不想依赖 starter 的监听器自动注册逻辑,也可以自己写一个配置类,用 ServletRegistrationBean 和 FilterRegistrationBean 注册 StatViewServlet 与 WebStatFilter。这种方式更灵活,适合需要动态读取账号密码或按环境控制是否开启监控的项目。
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DruidMonitorConfig {
@Bean
public ServletRegistrationBean<StatViewServlet> statViewServlet() {
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
bean.addInitParameter("loginUsername", "admin");
bean.addInitParameter("loginPassword", "admin123");
bean.addInitParameter("allow", "127.0.0.1");
return bean;
}
@Bean
public FilterRegistrationBean<WebStatFilter> webStatFilter() {
FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>(new WebStatFilter());
bean.addUrlPatterns("/*");
bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return bean;
}
}
手动注册时要注意,loginUsername 和 loginPassword 是 StatViewServlet 的初始化参数名,不能写错。exclusions 参数里多个静态资源后缀用英文逗号分隔,这行配置如果漏掉 /druid/*,监控页面自身的请求也可能被 WebStatFilter 统计干扰。
三、监控页打不开或返回 404 的排查
监控页打不开和 SQL 监控无数据要分开判断。404 一般说明 StatViewServlet 没有注册成功,或者访问路径不对;登录页能打开但 SQL 统计为空,则说明 filters 没有生效,或者数据源没有经过 StatFilter。
先检查 pom.xml 是否真的引入了 druid-spring-boot-starter,而不是只引入了 druid 基础包。只引入 druid 基础包不会自动注册监控 Servlet。然后看配置项 stat-view-servlet.enabled 是否为 true,url-pattern 是否写成 /druid/*,访问时是否携带了项目上下文路径。例如设置了 server.servlet.context-path=/api,那么监控地址就是 http://localhost:8080/api/druid/index.html,而不是直接访问 /druid。
如果项目集成了 Spring Security 或 Shiro,需要把监控路径放行。Spring Security 下通常可以写一个配置类,允许匿名访问 /druid/**,否则登录请求会被安全过滤器拦下来,表现就是一直跳转登录页或返回 403。
http.authorizeHttpRequests()
.requestMatchers("/druid/**").permitAll()
.anyRequest().authenticated();
还有一种情况是自定义了静态资源映射,导致 /druid 被静态资源处理器抢先返回 404。此时可以检查 WebMvcConfigurer 的 addResourceHandlers 是否覆盖了默认处理,必要时对监控路径单独做排除。总之 404 问题优先按依赖、配置、上下文路径、安全框架、静态资源映射这个顺序排查,基本能快速定位。
四、启动报错与 SQL 执行失败
启动阶段最常见的错误是驱动类找不到或驱动类名过时。MySQL 5.x 时代的 com.mysql.jdbc.Driver 在 MySQL 8 驱动中虽然仍保留,但会输出提醒,部分新版本驱动直接移除。Spring Boot 2.x 和 3.x 项目建议统一使用 com.mysql.cj.jdbc.Driver。另一个报错是 Public Key Retrieval is not allowed,这是因为 MySQL 8 默认使用 caching_sha2_password 认证,JDBC URL 中需要加上 allowPublicKeyRetrieval=true。
spring.datasource.url=jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
如果数据库连接本身没有问题,但启动初始化连接池时一直报 testWhileIdle 的校验失败,优先检查 validation-query 是否适配当前数据库。MySQL 下通常用 SELECT 1,Oracle 下则需要 SELECT 1 FROM DUAL。还要确认 URL 中 serverTimezone 参数是否带上,否则可能出现时区识别异常。
运行期 SQL 执行失败里,比较隐蔽的是 Druid 的 wall 防火墙拦截。典型日志会包含 sql injection violation。比如业务里有 update 关联表、delete 关联表或 insert ... select 语句,这些语句在默认 wall 规则中可能命中黑名单。如果确认不是注入风险,可以关闭 wall 过滤器,或者调整具体拦截项。
spring.datasource.druid.filter.wall.enabled=false
关闭 wall 会失去防注入能力,不建议直接在生产环境关闭。如果只是单条 SQL 必须执行,更推荐使用白名单语法配置。Druid wall 的 config 参数较多,遇到误拦截时可以先把日志中的拦截规则打印出来,再针对性放行。多语句场景下才需要开启 multi-statement-allow,普通 CRUD 不需要打开这个选项,否则会扩大 SQL 注入面。
五、多数据源场景下监控失效
当项目需要同时连接主库和从库、或连接两个不同业务库时,往往不能再用 starter 的自动配置,而是通过 @Configuration 手动创建多个 DataSource。手动创建时容易漏掉两个关键点:一是没有给每个 DruidDataSource 设置 filters=stat,wall,二是没有用 @Primary 标明主数据源,导致 MyBatis 或 JPA 自动装配时找不到唯一候选。
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.druid.primary")
public DataSource primaryDataSource() {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
dataSource.setFilters("stat,wall");
return dataSource;
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.secondary")
public DataSource secondaryDataSource() {
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
dataSource.setFilters("stat,wall");
return dataSource;
}
}
上面代码用 @ConfigurationProperties 分别绑定 primary 和 secondary 两个前缀,这样配置文件仍然可以保持清晰。每个数据源都调用 setFilters("stat,wall"),SQL 监控才会采集完整。只给其中一个数据源设置 filters,监控页里只能看到该数据源的执行记录,另一个数据源始终空白,这种现象很容易被误认为监控功能没生效。
多数据源还需要关注事务和 Mapper 扫描范围。@Primary 决定默认注入的数据源,@MapperScan 的 sqlSessionFactoryRef 也要与对应数据源匹配,否则 mapper 会去错误的数据源里找表。事务管理器需要分别创建,并在 @Transactional 注解中指定 transactionManager,不要只使用默认事务管理器。
spring.datasource.druid.primary.url=jdbc:mysql://localhost:3306/primary_db?useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.druid.primary.username=root spring.datasource.druid.primary.password=123456 spring.datasource.druid.primary.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.druid.secondary.url=jdbc:mysql://localhost:3306/secondary_db?useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.druid.secondary.username=root spring.datasource.druid.secondary.password=123456 spring.datasource.druid.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
配置文件可以这样组织:主库和从库的前缀分别为 spring.datasource.druid.primary 和 spring.datasource.druid.secondary,连接池参数可以复用,但 URL 和账号通常不同。需要特别注意的是,手动创建数据源后,starter 自动配置不会自动读取 spring.datasource.druid 下的通用参数,必须在 @ConfigurationProperties 中绑定自己的前缀,否则连接池容量、校验参数都会丢失。
六、连接池参数调优建议
Druid 连接池是否稳定,很大程度上取决于 initial-size、min-idle、max-active 和 max-wait 这几个参数。initial-size 和 min-idle 可以保持一致,避免启动后还要频繁创建连接。max-active 要根据数据库实际能承受的连接数来设,不是越大越好。应用实例很多时,总连接数等于实例数乘以 max-active,如果超过数据库 max_connections,就会出现拒绝连接或连接超时。
max-wait 控制获取连接时的最大等待时间,生产环境建议设置为 5000 到 10000 毫秒,超时后快速失败,避免请求线程长时间阻塞。validation-query 在 MySQL 下使用 SELECT 1 就足够,test-on-borrow 不建议打开,因为每次借连接都执行一次校验会明显增加数据库开销。空闲检测通过 test-while-idle 配合 time-between-eviction-runs-millis 更合适。
对于使用预编译语句较多的系统,建议开启 pool-prepared-statements 并把 max-pool-prepared-statement-per-connection-size 设置为 20 左右。这个参数控制单个连接中 PreparedStatement 对象缓存数量,过大会占用较多内存,过小则起不到复用效果。慢 SQL 阈值在开发环境可以设置成 1000 毫秒,生产环境先设置 2000 到 3000 毫秒,再根据实际监控数据逐步收紧。
spring.datasource.druid.max-active=30 spring.datasource.druid.max-wait=10000 spring.datasource.druid.pool-prepared-statements=true spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
按照这套配置思路,Druid 连接池可以提供稳定的连接管理和足够的监控信息。遇到问题时不要只盯着报错堆栈,先确认连接池配置是否正确加载、监控 Servlet 是否注册、filters 是否对目标数据源生效,这三处检查完,大多数整合问题都能定位。
Spring BootDruid连接池数据库连接池修改时间:2026-09-25 08:53:33