前言
在上一篇我们聊完了数据库锁,今天我们来聊聊应用服务器与数据库之间的桥梁——数据库连接池 (Database Connection Pool)。
为什么要用连接池? 因为建立一个数据库连接(TCP三次握手 + 验证账号密码 + 建立Session)是非常昂贵的操作。如果每次请求都创建一个新连接,用完就关,你的数据库光是忙着处理连接和断开就把 CPU 吃光了。
连接池就像一个**“资源池”**,预先建立好一批连接,借给你用,用完你还回来,不要关闭,供下一个人继续用。
目前 Java 界的主流连接池是 HikariCP(Spring Boot 2.x/3.x 默认)和 Druid(阿里出品,监控强大)。本文以通用的配置逻辑为主进行讲解。
1. 四大核心配置参数
无论你用 Hikari 还是 Druid,这 4 个参数是必须理解的:
1. maximumPoolSize (最大连接数)
- 含义: 池子里最多能有多少个连接(包括正在用的和空闲的)。
- 重要性: ⭐⭐⭐⭐⭐
- 误区: 越大越好?错! 很多新手直接设成 1000,觉得这样并发就高。实际上,数据库的 CPU 核心数是有限的,过多的连接会导致频繁的上下文切换 (Context Switching),反而降低性能。
2. minimumIdle (最小空闲连接数)
- 含义: 池子里最少要保留多少个“备胎”连接,随时待命。
- 建议: 官方(HikariCP)建议 minimumIdle = maximumPoolSize。
- 理由: 如果设为不同值,连接池会不断地在流量波动时扩容和缩容,造成不必要的开销。不如直接固定大小(Fixed Size)。
3. connectionTimeout (连接等待超时时间)
- 含义: 当池子里的连接都被借光了,新来的请求愿意等多久?
- 默认值: 通常是 30秒。
- 调优: 建议调小到 1秒 - 3秒。如果 3秒都拿不到连接,说明数据库压力太大或连接泄露了,让它快速失败(Fail Fast),不要让线程卡那里死等,拖垮整个服务。
4. maxLifetime (连接最大存活时间)
- 含义: 一个连接最长能活多久。
- 重要性: 必须 小于 数据库服务端的
wait_timeout。 - 理由: 如果 MySQL 默认 8小时断开连接,而你的池子里的连接活了 9小时,当你拿到这个连接去查库时,就会报错“Pipe broken”。建议设置为 30分钟 (1800000ms)。
2. 灵魂拷问:连接池多大才合适?
这是面试和实战中最大的难题。
PostgreSQL 官方和 HikariCP 作者给出了一个广受认可的黄金公式:
连接数 = ((核心数 * 2) + 有效磁盘数)
假如你的数据库服务器是 4核 CPU:
connections = ((4 * 2) + 1) = 9
你没看错,即使是生产环境,10 - 20 个连接往往就足够支撑几千并发了!
为什么这么小?因为计算机 I/O 速度极快。对于 4核 CPU,它同一时刻真的只能做 4 件事。给你 1000 个连接,996 个都在排队(Wait),而且 CPU 还要耗费时间在这些线程之间切来切去,得不偿失。
结论:
- 小规模应用: 10 - 20
- 大规模应用: 20 - 50(根据压测调整)
- 切记: 瓶颈通常在数据库的磁盘 I/O,而不是连接数不够。
3. Druid 连接池的“杀手锏”
如果你使用的是阿里的 Druid,它除了连接池功能,还有一个大杀器——监控。
在 application.yml 中配置好 filter 后,访问 /druid/index.html,你可以看到:
- SQL监控: 哪些 SQL 执行最慢?(Slow SQL)
- 防火墙: 拦截恶意的 SQL 注入。
- 连接泄漏监测:
removeAbandoned功能,自动强制关闭那些借出去很久没还的连接(通常是代码 bug 导致的)。
4. 常见配置清单 (Spring Boot版)
以下是一个标准的、经过优化的配置模板(以 Hikari 为例):
YAML
spring: datasource: hikari: # 1. 池大小:固定为 10 maximum-pool-size: 10 minimum-idle: 10 # 2. 快速失败:等待超过 3秒 就报错 connection-timeout: 3000 # 3. 这里的 idle-timeout 要小于 max-lifetime idle-timeout: 300000 # 4. 防止连接过久导致数据库端断开,设为 30分钟 max-lifetime: 1800000 # 5. 测试连接是否有效的查询语句 connection-test-query: SELECT 1
总结
数据库连接池的调优,核心在于**“克制”**。 不要妄图通过增加连接数来解决慢查询问题。如果 SQL 慢,去加索引;如果连接不够用,先检查代码有没有及时 close 连接。
记住黄金公式,设置合理的 Timeout,你的数据库会感谢你的。