很多同学问连接池到底选 HikariCP 还是 Druid,参数怎么调,今天统一回答。跟着我操作一遍,你也能掌握。


一、为什么需要连接池?(30 秒理解原理)

先搞清楚一件事:每次查询都新建连接,代价有多大

// 不用连接池——每次查询都新建连接
Connection conn = DriverManager.getConnection(url, user, password); // 耗时 50-200ms
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
rs.close(); stmt.close(); conn.close(); // 连接销毁

一次 TCP 握手 + SSL 协商 + 认证,大约 50-200ms。如果你的应用每秒 1000 次查询,光建连接就要花掉 50-200 秒。

连接池的工作原理

MySQL

连接池 Connection Pool

应用程序

获取连接 < 1ms

获取连接 < 1ms

获取连接 < 1ms

请求线程1

请求线程2

请求线程3

连接池管理器

Conn 1 空闲

Conn 2 使用中

Conn 3 空闲

Conn 4 空闲

Conn 5 空闲

MySQL Server

核心就一句话:连接池提前建好连接,重复使用,避免每次查询都 TCP 握手。取连接耗时 < 1ms,对比新建连接的 50-200ms,性能提升 50-200 倍。


二、HikariCP 配置(2 分钟)

HikariCP 是目前 Java 生态最快的连接池(Spring Boot 2.x 默认),零依赖、轻量、性能极致。

2.1 Maven 依赖

<!-- HikariCP -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.1.0</version>
</dependency>

<!-- MySQL JDBC 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

2.2 最小可用配置(Java 原生)

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai");
config.setUsername("root");
config.setPassword("123456");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");

// 核心参数(先只配这 3 个,够用了)
config.setMaximumPoolSize(10);          // 最大连接数
config.setMinimumIdle(5);               // 最小空闲连接
config.setConnectionTimeout(30000);     // 获取连接超时时间(毫秒)

HikariDataSource ds = new HikariDataSource(config);

// 测试连接
try (Connection conn = ds.getConnection()) {
    System.out.println("连接成功!");
}

2.3 Spring Boot 配置(推荐)

如果你用 Spring Boot,不需要写一行 Java 代码,application.yml 就够了:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    
    # HikariCP 配置
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      pool-name: MyHikariPool

2.4 核心参数详解

参数 默认值 说明 推荐值
maximumPoolSize 10 连接池最大连接数(含空闲+使用中) 见下方计算公式
minimumIdle 10 最小空闲连接数 建议 = maximumPoolSize
connectionTimeout 30000ms 从池中获取连接的超时时间 30000(30秒)
idleTimeout 600000ms 空闲连接存活时间 600000(10分钟)
maxLifetime 1800000ms 连接最大存活时间(到期后销毁重建) 1800000(30分钟)
poolName 自动生成 连接池名称(日志中显示) 按项目命名

最大连接数怎么设置?

HikariCP 作者推荐的公式:

连接数 = CPU 核心数 × 2 + 有效磁盘数

举例:

  • 4 核 CPU + 1 块 SSD → 4 × 2 + 1 = 9,取 10
  • 8 核 CPU + 1 块 SSD → 8 × 2 + 1 = 17,取 20

经验之谈:不要盲目把连接数设很大。MySQL 默认的 max_connections 是 151,连接池设 200 毫无意义,反而增加 MySQL 端的线程开销。大多数中小应用,10-20 个连接足够


三、Druid 配置(2 分钟)

Druid 是阿里开源的连接池,最大特色是自带监控面板,国内很多企业在用。

3.1 Maven 依赖

<!-- Druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.21</version>
</dependency>

<!-- MySQL JDBC 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

3.2 最小可用配置(Java 原生)

DruidDataSource ds = new DruidDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai");
ds.setUsername("root");
ds.setPassword("123456");
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");

// 核心参数
ds.setInitialSize(5);              // 初始连接数
ds.setMinIdle(5);                  // 最小空闲连接
ds.setMaxActive(10);               // 最大活跃连接
ds.setMaxWait(30000);              // 获取连接最大等待时间(毫秒)

// 验证连接有效性(推荐开启)
ds.setValidationQuery("SELECT 1");
ds.setTestWhileIdle(true);         // 空闲时检测连接有效性
ds.setTestOnBorrow(false);         // 获取时不检测(性能考虑)
ds.setTestOnReturn(false);         // 归还时不检测

// 初始化(必须调用)
ds.init();

3.3 Spring Boot 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 10
      max-wait: 30000
      
      # 连接有效性检测
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      
      # 监控配置
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        login-username: admin
        login-password: admin123
      
      # 慢 SQL 记录
      filter:
        stat:
          enabled: true
          slow-sql-millis: 2000
          log-slow-sql: true

3.4 Druid 监控面板

配置 stat-view-servlet 后,访问 http://localhost:8080/druid/ 即可打开内置的 Web 监控面板:

Druid 监控面板核心功能

  • 数据源监控:活跃连接数、空闲连接数、等待线程数一目了然
  • SQL 监控:每条 SQL 的执行次数、平均耗时、最慢耗时、解析次数
  • URL 监控:每个接口的数据库调用情况和耗时
  • Spring 监控:各 Bean 的 SQL 执行情况
  • 慢 SQL 记录:超过阈值(如 2 秒)的 SQL 自动记录到日志

这是 Druid 最大的差异化优势。如果你需要内置监控、不想额外搭 Prometheus + Grafana,Druid 是很好的选择。


四、HikariCP vs Druid 选型对照

4.1 核心对比

维度 HikariCP Druid
性能 极快(字节码优化、无锁设计) 快(但略逊于 HikariCP)
监控 无内置监控(需接入 JMX/Prometheus) 内置 Web 监控面板
SQL 防火墙 支持(防 SQL 注入、黑白名单)
慢 SQL 检测 内置
代码量 约 2 万行 约 15 万行
社区 全球活跃 国内活跃
Spring Boot 默认集成 需手动指定 type

4.2 选型建议

追求极致性能、有独立监控系统 → HikariCP
需要内置监控、SQL 审计、中小团队 → Druid

我的建议:如果你不确定选哪个,先用 HikariCP(Spring Boot 默认)。等需要监控的时候再切 Druid,切换成本很低——改个依赖和配置就行。


五、常见报错排查

报错 1:Connection is not available, request timed out after 30000ms

原因:连接池耗尽,所有连接都被占用,新请求等待超时。

排查步骤

// 1. 打印连接池状态(HikariCP)
HikariPoolMXBean poolMXBean = ds.getHikariPoolMXBean();
System.out.println("活跃连接: " + poolMXBean.getActiveConnections());
System.out.println("空闲连接: " + poolMXBean.getIdleConnections());
System.out.println("总连接数: " + poolMXBean.getTotalConnections());
System.out.println("等待线程: " + poolMXBean.getThreadsAwaitingConnection());

常见原因与修复

原因 修复方法
连接泄漏(获取后没关闭) 使用 try-with-resources 确保连接关闭
慢 SQL 占用连接太久 优化 SQL,减少连接占用时间
最大连接数设小了 适当调大 maximumPoolSize
并发量确实大 考虑读写分离或分库

报错 2:MySQL: Too many connections

原因:MySQL 服务端的连接数达到上限(默认 151)。

排查

-- 查看当前连接数
SHOW STATUS LIKE 'Threads_connected';

-- 查看最大连接数限制
SHOW VARIABLES LIKE 'max_connections';

-- 查看各用户的连接分布
SELECT user, host, COUNT(*) AS connections
FROM information_schema.processlist
GROUP BY user, host;

修复

-- 临时调大(重启失效)
SET GLOBAL max_connections = 500;

-- 永久生效(修改 my.cnf)
-- [mysqld]
-- max_connections = 500

注意:MySQL 连接数不是越大越好。每个连接大约占用 256KB-几 MB 内存,500 个连接就是 128MB+。更关键的是,MySQL 线程切换开销会随连接数增加而增大。

报错 3:Communications link failure

原因:MySQL 主动关闭了空闲连接(默认 wait_timeout = 8 小时),但连接池不知道,还拿着已关闭的连接。

修复(两种方案)

# 方案 1:HikariCP - 设置 maxLifetime 小于 MySQL 的 wait_timeout
hikari:
  max-lifetime: 1800000  # 30分钟,远小于 MySQL 默认 8 小时

# 方案 2:Druid - 开启空闲检测
druid:
  validation-query: SELECT 1
  test-while-idle: true
  time-between-eviction-runs-millis: 60000  # 每分钟检测一次

六、参数速查表

HikariCP                      Druid                       说明
──────────────────────────────────────────────────────────────────
maximumPoolSize        ↔  maxActive                 最大连接数
minimumIdle            ↔  minIdle                   最小空闲连接
connectionTimeout      ↔  maxWait                   获取连接超时
idleTimeout            ↔  minEvictableIdleTime      空闲连接回收时间
maxLifetime            ↔  phyTimeoutMillis           连接最大存活时间
poolName               ↔  name                      连接池名称
─                      ↔  initialSize               初始连接数(HikariCP 无)
─                      ↔  validationQuery           验证 SQL(HikariCP 无)

总结

连接池配置其实不复杂,核心就记住三点:

  1. 连接数不要设太大——按 CPU 核心数 × 2 + 磁盘数 的公式来
  2. 必须设置连接超时和最大存活时间——避免连接泄漏和断连问题
  3. 选 HikariCP 还是 Druid 取决于是否需要内置监控——不需要就选 HikariCP

配置好了连接池,数据库的性能才能发挥出来。后续我会继续分享 SQL 调优、慢查询分析、索引优化 这些话题,跟着我一篇篇学,数据库这块就没问题了。

有问题评论区见。


喜欢把枯燥的技术文档变成"手把手教程"。关注我,数据库这块我们一起搞定。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐