5 分钟搞定 MySQL 连接池配置与调优(HikariCP / Druid 一篇全)

0 阅读7分钟

十五年数据库相关经验,做过 DBA、架构师、技术顾问。喜欢把枯燥的技术文档变成"手把手教程",不求"颠覆",只求"靠谱"。不讲空话,只讲怎么连、怎么写、怎么优化。


很多同学问连接池到底选 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 秒。

连接池的工作原理

image.png

核心就一句话:连接池提前建好连接,重复使用,避免每次查询都 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 核心参数详解

参数默认值说明推荐值
maximumPoolSize10连接池最大连接数(含空闲+使用中)见下方计算公式
minimumIdle10最小空闲连接数建议 = maximumPoolSize
connectionTimeout30000ms从池中获取连接的超时时间30000(30秒)
idleTimeout600000ms空闲连接存活时间600000(10分钟)
maxLifetime1800000ms连接最大存活时间(到期后销毁重建)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 监控面板

Druid 监控面板核心功能

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

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


四、HikariCP vs Druid 选型对照

4.1 核心对比

维度HikariCPDruid
性能极快(字节码优化、无锁设计)快(但略逊于 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 调优、慢查询分析、索引优化 这些话题,跟着我一篇篇学,数据库这块就没问题了。

有问题评论区见。


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