十五年数据库相关经验,做过 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 秒。
连接池的工作原理:
核心就一句话:连接池提前建好连接,重复使用,避免每次查询都 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 监控面板
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 无)
总结
连接池配置其实不复杂,核心就记住三点:
- 连接数不要设太大——按 CPU 核心数 × 2 + 磁盘数 的公式来
- 必须设置连接超时和最大存活时间——避免连接泄漏和断连问题
- 选 HikariCP 还是 Druid 取决于是否需要内置监控——不需要就选 HikariCP
配置好了连接池,数据库的性能才能发挥出来。后续我会继续分享 SQL 调优、慢查询分析、索引优化 这些话题,跟着我一篇篇学,数据库这块就没问题了。
有问题评论区见。
喜欢把枯燥的技术文档变成"手把手教程"。关注我,数据库这块我们一起搞定。