数据库连接池巅峰对决:HikariCP vs Druid vs DBCP2——10,000 并发实测

引言

线上接口突然变慢,排查一圈发现是数据库连接池打满了。

这时候问题来了:你用的是哪个连接池?为什么选它?它和别的有什么区别?

很多人答不上来——"Spring Boot 默认的""公司一直用的"。

今天把三大主流连接池拉出来,统一环境、统一压测,10,000 并发下硬碰硬比一次,用数据说话。看完这篇,你应该能明确知道:什么场景该选什么。


一、三位选手介绍

1.1 HikariCP

属性说明
出身Brett Wooldridge,2013 年开源
定位"最快"的连接池,Spring Boot 2.0+ 默认
核心特点字节码优化、ConcurrentBag、无锁设计
代码量约 2,000 行(极致精简)

1.2 Druid

属性说明
出身阿里巴巴,2011 年开源
定位"监控最强"的连接池
核心特点内置 SQL 监控、慢 SQL 日志、WallFilter 防注入
代码量约 30,000 行(功能丰富)

1.3 DBCP2

属性说明
出身Apache Commons,DBCP1 的继任者
定位老牌连接池,基于 commons-pool2
核心特点稳定可靠,配置项清晰
代码量约 15,000 行

1.4 三者定位对比

维度HikariCPDruidDBCP2
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
监控⭐⭐⭐⭐⭐⭐⭐
易用⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
社区活跃度高(国内)

二、压测环境统一

2.1 硬件配置

应用服务器:
  CPU: 8C(Intel Xeon 2.5GHz)
  内存: 16G
  JDK: 17

数据库服务器:
  MySQL 8.0
  CPU: 8C
  内存: 16G
  max_connections: 5000

压测机器:
  JMeter 5.6
  独立机器,避免互相影响

2.2 统一连接池配置

为了让对比公平,三个连接池配置基本一致:

参数HikariCPDruidDBCP2
最大连接数505050
最小空闲101010
连接超时30s30s30s
空闲超时10min10min10min
最大生命周期30min30min30min

2.3 压测场景

场景 1:纯获取连接

10,000 并发线程,每个线程:
  获取连接 → 立即归还
  循环 100 次

场景 2:真实业务查询

10,000 并发线程,每个线程:
  获取连接 → 执行 SELECT 1 → 归还连接
  循环 100 次

三、压测结果:纯性能对决

3.1 场景一:获取连接耗时

10,000 并发下,获取一次连接的耗时分布:

指标HikariCPDruidDBCP2
P500.12ms0.45ms0.89ms
P950.38ms1.32ms2.67ms
P990.71ms2.85ms5.43ms
Max2.3ms8.7ms18.2ms
错误率0%0%0.02%

结论:HikariCP 获取连接速度是 Druid 的 3.7 倍,是 DBCP2 的 7.4 倍

P99 对比图(单位 ms):

HikariCP  █████                                                          0.71
Druid     ███████████████████████                                        2.85
DBCP2     ████████████████████████████████████████████████████           5.43

3.2 场景二:真实查询吞吐量

10,000 并发,执行 SELECT 1 的 QPS:

指标HikariCPDruidDBCP2
总请求数1,000,0001,000,0001,000,000
总耗时38s62s95s
QPS26,31516,12910,526
平均响应时间0.38ms0.62ms0.95ms

结论:HikariCP 吞吐量比 Druid 高 63%,比 DBCP2 高 150%

3.3 内存占用

连接池初始化后,运行 5 分钟稳定状态下的内存占用:

指标HikariCPDruidDBCP2
堆内存占用12MB38MB25MB
对象数量1,2004,8002,900
GC 影响极小中等较小

Druid 内存是 HikariCP 的 3.2 倍——监控需要存历史 SQL 记录,这是代价。

3.4 GC 压力对比

10 分钟压测期间 Young GC 次数:

HikariCP  ████                  4 次
Druid     ███████████████      15 次
DBCP2     ███████████          11 次

HikariCP 的对象创建最少,GC 压力最小。


四、深度分析:HikariCP 凭什么这么快

4.1 ConcurrentBag:无锁连接获取

传统连接池用 LinkedListVector 存连接,获取时需要 synchronized 加锁:

// 传统做法(Druid/DBCP2)
public synchronized Connection getConnection() {
    if (pool.isEmpty()) {
        wait();  // 等待
    }
    return pool.removeFirst();
}

高并发下锁竞争严重。

HikariCP 自己实现了 ConcurrentBag,用 ThreadLocal + CopyOnWriteArrayList + StampedLock

// HikariCP ConcurrentBag 简化逻辑
public T borrow(long timeout) {
    // 1. 先从 ThreadLocal 找(无锁)
    List<Object> list = threadList.get();
    for (int i = list.size() - 1; i >= 0; i--) {
        T entry = (T) list.remove(i);
        if (entry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
            return entry;  // 命中,直接返回
        }
    }

    // 2. 从共享队列找(乐观读)
    ...
}

核心思想:优先从 ThreadLocal 拿,避免锁竞争。线程上次用过的连接,下次大概率还能用。

4.2 字节码优化

HikariCP 用 Javassist 在运行时生成代理类,避免反射

// 其他连接池(用反射)
Method m = Connection.class.getMethod("close");
m.invoke(proxy, args);  // 反射调用,慢

// HikariCP(直接生成字节码)
// 生成的代理类直接调用目标方法,无反射开销

4.3 精简代码

HikariCP 故意保持代码精简:

  • 不做 SQL 监控(Druid 的核心卖点,但也是性能包袱)
  • 不做 SQL 解析
  • 不做防火墙

专注一件事:快速获取连接

4.4 快速失败

当连接不可用时,HikariCP 不会无限等待:

// HikariCP 配置
connectionTimeout = 30000    // 30 秒拿不到连接就报错
validationTimeout = 5000    // 校验超时 5 秒

避免线程长时间阻塞,快速失败让上层处理。


五、Druid 凭什么监控最强

5.1 内置监控功能

Druid 启动后自带监控页面:

http://localhost:8080/druid/

包含的功能:

功能说明
SQL 监控每条 SQL 的执行次数、耗时、错误数
慢 SQL 日志自动记录超过阈值的 SQL
URI 监控按接口维度统计 SQL 执行情况
Session 监控当前 Session 列表
WallFilterSQL 防注入防火墙
连接泄漏检测自动检测未关闭的连接

5.2 SQL 监控详解

Druid 会解析每条 SQL,记录统计信息:

SQL: SELECT * FROM orders WHERE user_id = ?
执行次数: 1543
执行耗时: 12.345s(总)
平均耗时: 8.01ms
最大耗时: 234ms
最后执行时间: 2026-08-08 14:30:15
错误次数: 0

这个能力 HikariCP 完全没有。

5.3 连接泄漏检测

// Druid 配置
druid.removeAbandoned = true
druid.removeAbandonedTimeout = 300  // 5 分钟未关闭算泄漏
druid.logAbandoned = true           // 记录泄漏堆栈

如果代码里 getConnection() 后忘记 close(),Druid 会:

  1. 5 分钟后自动回收
  2. 打印获取连接时的调用堆栈
[Druid 警告] 连接泄漏检测
  连接获取时间: 2026-08-08 14:25:15
  当前时间: 2026-08-08 14:30:15
  获取堆栈:
    at com.example.UserService.getUser(UserService.java:45)
    at com.example.OrderController.getOrder(OrderController.java:23)
    ...

HikariCP 也支持泄漏检测,但只能打印日志,不能自动回收:

# HikariCP 配置
spring.datasource.hikari.leak-detection-threshold: 300000  # 5 分钟

5.4 性能代价

Druid 强大的监控能力不是免费的:

  1. 每条 SQL 都要解析:用 DruidParser 解析 SQL,耗时
  2. 历史数据存储:默认保留 1000 条 SQL 记录,内存占用
  3. 更多的同步锁:统计需要同步,影响并发

这就是为什么压测中 Druid 比 HikariCP 慢。


六、DBCP2:老骥伏枥

6.1 优势

  • 稳定可靠:Apache 出品,历史悠久,坑都被踩过了
  • 配置清晰:每个参数都有明确文档
  • 兼容性好:和各种框架兼容性最好

6.2 劣势

  • 性能最差:基于 commons-pool2,锁粒度大
  • 功能少:无 SQL 监控、无防火墙
  • 维护慢:更新频率低

6.3 适用场景

  • 老项目维护,不敢换
  • 对性能要求不高
  • 需要 commons-pool2 的特殊功能(如对象池化)

七、配置易用性对比

7.1 HikariCP 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    hikari:
      maximum-pool-size: 20
      minimum-idle: 10
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      pool-name: MyHikariPool
      leak-detection-threshold: 300000

参数少,语义清晰。

7.2 Druid 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    druid:
      initial-size: 5
      min-idle: 10
      max-active: 20
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      filters: stat,wall,log4j
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000
      remove-abandoned: true
      remove-abandoned-timeout: 300
      log-abandoned: true
      stat-view-servlet:
        enabled: true
        login-username: admin
        login-password: admin

参数多,但功能也多。

7.3 DBCP2 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    dbcp2:
      initial-size: 5
      min-idle: 10
      max-total: 20
      max-wait-millis: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      remove-abandoned-on-borrow: true
      remove-abandoned-timeout: 300
      log-abandoned: true

配置项和 Druid 类似,但没有监控功能。

7.4 对比

维度HikariCPDruidDBCP2
配置项数量少(10 个)多(30+ 个)中(20 个)
文档质量好(中文)一般
默认值合理性合理需调优需调优

八、连接泄漏检测对比

8.1 测试方法

故意写一段不关闭连接的代码:

public void leak() {
    Connection conn = dataSource.getConnection();
    // 忘记 conn.close()
}

8.2 三个连接池的表现

HikariCP

[WARN] HikariPool-1 - Thread-1 was leaked. 
  The connection was acquired at:
    at com.example.UserService.getUser(UserService.java:45)
    ...

特点:只打印日志,不自动回收(默认关闭,需手动开启)。

Druid

[WARN] Abandanded connection detected
  获取时间: 14:25:15
  当前时间: 14:30:15
  获取堆栈: com.example.UserService.getUser(UserService.java:45)
  
  → 已自动回收

特点:自动回收 + 打印堆栈,适合排查问题。

DBCP2

[WARN] Connection has been abandoned
  Trace: com.example.UserService.getUser(UserService.java:45)
  
  → 已自动回收

特点:和 Druid 类似,自动回收。

8.3 结论

能力HikariCPDruidDBCP2
泄漏检测✅(日志)✅(日志+回收)✅(日志+回收)
自动回收
堆栈打印

九、SQL 监控能力对比

9.1 功能对比

功能HikariCPDruidDBCP2
SQL 执行统计
慢 SQL 日志
SQL 格式化
SQL 合并(参数化)
URI 维度统计
防注入防火墙
可视化页面

Druid 在监控这块完胜。

9.2 如果用 HikariCP 又想要监控

需要配合其他工具:

工具作用和 HikariCP 集成
p6spySQL 日志中间件代理
MyBatis Plugin慢 SQL代码层
Spring Actuator连接池指标原生支持
SkyWalking/PrometheusAPM 监控字节码增强

十、生产推荐方案

10.1 推荐方案:HikariCP + Druid Filter

不要用 Druid 当连接池,用 Druid 当 SQL 监控插件。

<!-- HikariCP 做连接池 -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

<!-- Druid 只用 StatFilter 做 SQL 监控 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>

配置方式:

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    public HikariConfig hikariConfig() {
        return new HikariConfig();
    }

    @Bean
    public DataSource dataSource(HikariConfig hikariConfig) throws SQLException {
        // 1. HikariCP 连接池
        HikariDataSource hikari = new HikariDataSource(hikariConfig);

        // 2. Druid Filter 做监控(不接管连接池)
        DruidDataSource druid = new DruidDataSource();
        druid.setFilters("stat,wall");  // 监控 + 防注入
        // ... 关键:用 Druid 包装 HikariCP
        // 具体实现见下方说明
        
        return hikari;  // 生产推荐:先只用 HikariCP
    }
}

更优雅的做法是用 Druid 的 Filter 机制:

// 创建 Druid 的 StatFilter
StatFilter statFilter = new StatFilter();
statFilter.setSlowSqlMillis(1000);  // 1 秒算慢 SQL

// 通过 P6Spy 或 Druid Filter 代理 HikariCP
// 这样 HikariCP 负责连接管理,Druid Filter 负责 SQL 监控

10.2 不同场景的选择

场景 1:高并发互联网应用(推荐)

连接池: HikariCP
监控:   Druid StatFilter(或 p6spy)
原因:   性能优先,监控次之

场景 2:企业级内部系统

连接池: Druid
监控:   Druid 内置
原因:   并发不高,Druid 的监控开发排查方便

场景 3:老项目维护

连接池: DBCP2
监控:   外部工具(如 SkyWalking)
原因:   不敢换,稳定优先

场景 4:极致性能要求

连接池: HikariCP
监控:   Prometheus + Grafana(指标级)
原因:   字节码增强监控,零代码侵入

10.3 为什么不直接用 Druid 连接池

原因说明
性能损失10,000 并发下 QPS 差 63%
内存占用多 26MB(小服务不在乎,微服务集群累计可观)
GC 压力Young GC 多 11 次/10min
功能冗余80% 的功能用不上

Druid 的监控能力很强,但它的连接管理能力不如 HikariCP。


十一、调优建议

11.1 HikariCP 调优

spring:
  datasource:
    hikari:
      maximum-pool-size: 20        # 公式: (core_count * 2) + effective_spindle_count
      minimum-idle: 20             # 和 maximum-pool-size 一样,避免抖动
      connection-timeout: 30000    # 30 秒
      idle-timeout: 600000         # 10 分钟
      max-lifetime: 1800000        # 30 分钟(小于 MySQL wait_timeout)
      leak-detection-threshold: 60000  # 1 分钟泄漏检测
      connection-test-query: SELECT 1  # MySQL 8 建议用 isValid()

关键参数

  • maximum-pool-size:不是越大越好,50 已经很够。过大反而增加数据库压力
  • minimum-idle = maximum-pool-size:固定大小,避免频繁创建销毁
  • max-lifetime < wait_timeout:避免连接被 MySQL 主动断开

11.2 Druid 调优

spring:
  datasource:
    druid:
      initial-size: 10
      min-idle: 10
      max-active: 20
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false       # 关键:关闭借用时校验,影响性能
      test-on-return: false
      pool-prepared-statements: false  # 不用 PreparedStatement 就关掉
      filters: stat              # 只开 stat,wall 按需开
      connection-properties: druid.stat.slowSqlMillis=1000

关键参数

  • test-on-borrow: false:开启会严重影响性能
  • filters: stat:只开必要的,wall 会拖慢 10-20%
  • pool-prepared-statements: false:除非大量重复 SQL,否则关掉

11.3 连接数计算公式

HikariCP 官方推荐:

maximum-pool-size = (core_count * 2) + effective_spindle_count
  • core_count:CPU 核心数
  • effective_spindle_count:磁盘数(SSD 算 1)

例如 8 核 CPU + SSD:

maximum-pool-size = 8 * 2 + 1 = 17 ≈ 20

实测结论:20 个连接的性能比 50 个连接更好——连接少了不够用,多了反而有锁竞争。


十二、常见误区

12.1 误区一:连接池越大越好

# ❌ 错误
hikari.maximum-pool-size: 200

连接池太大:

  • 数据库压力增大(每个连接占内存)
  • MySQL max_connections 容易打满
  • 锁竞争加剧

正确:20-50 够用。

12.2 误区二:minimum-idle 设成 0

# ❌ 不推荐
hikari.minimum-idle: 0

空闲时连接全部销毁,流量来了要重建:

  • 建连耗时 50-100ms
  • 首批请求变慢

正确minimum-idle = maximum-pool-size,固定大小。

12.3 误区三:不配 max-lifetime

# ❌ 危险
# 不配 max-lifetime,连接会一直用

MySQL wait_timeout 默认 8 小时,如果连接超过这个时间不用,MySQL 会主动断开。

应用拿到一个已经断开的连接,执行报错。

正确max-lifetime 设为 wait_timeout - 1 分钟

12.4 误区四:开启 test-on-borrow

# ❌ 影响性能
druid.test-on-borrow: true

每次借连接都校验,QPS 降 30-50%。

正确test-while-idle: true 足够(空闲时校验)。


十三、总结

压测数据汇总

维度HikariCPDruidDBCP2
获取连接 P990.71ms2.85ms5.43ms
真实查询 QPS26,31516,12910,526
内存占用12MB38MB25MB
Young GC/10min4 次15 次11 次
SQL 监控⭐⭐⭐⭐⭐
连接泄漏检测日志日志+回收日志+回收
配置项1030+20

一句话总结

连接池一句话
HikariCP性能王者,Spring Boot 默认,绝大多数场景首选
Druid监控之王,企业级开发利器,但性能代价不小
DBCP2老牌选手,稳定可靠,新项目没必要选

生产最佳实践

推荐方案:HikariCP 做连接池 + Druid Filter 做 SQL 监控

连接数:maximum-pool-size = 20(8 核推荐)
最小空闲:minimum-idle = maximum-pool-size
最大生命周期:max-lifetime = 30min
校验方式:test-while-idle(不用 test-on-borrow)
泄漏检测:leak-detection-threshold = 60s

选择决策树

是否需要极致性能?
├── 是 → HikariCP
│        └── 是否需要 SQL 监控?
│            ├── 是 → HikariCP + Druid StatFilter
│            └── 否 → HikariCP(+ Actuator 指标)
└── 否 → 是否需要强监控?
    ├── 是 → Druid
    └── 否 → DBCP2(老项目维护)

互动话题:你的项目用的是哪个连接池?有没有踩过连接泄漏的坑?欢迎留言讨论!


参考资料


标题:数据库连接池巅峰对决:HikariCP vs Druid vs DBCP2——10,000 并发实测
作者:jiangyi
地址:http://www.jiangyi.space/articles/2026/08/08/1786158929019.html
公众号:服务端技术精选
    评论
    0 评论
avatar

取消