数据库连接池优化:HikariCP与Druid实战
数据库连接池,说白了就是MES系统的命脉。我见过太多系统,业务逻辑写得再漂亮,最后都死在连接池上。今天咱们就聊聊HikariCP和Druid这两个主流连接池,我会把配置参数、踩坑经验都抖出来。
核心观点:连接池不是越大越好,也不是越快越好。关键是要找到那个「刚刚好」的点。
2.1 连接池的核心参数
先说说最关键的几个参数。我个人习惯,不管用哪个连接池,都会先盯住这三个:最大连接数、超时时间、连接泄漏检测。
| 参数名 | HikariCP | Druid | 我的建议值 |
|---|---|---|---|
| 最大连接数 | maximumPoolSize | maxActive | CPU核心数×2 + 1 |
| 最小空闲连接 | minimumIdle | minIdle | 最大连接数的1/4 |
| 连接超时 | connectionTimeout | maxWait | 30000ms(30秒) |
| 空闲超时 | idleTimeout | minEvictableIdleTimeMillis | 600000ms(10分钟) |
| 最大存活时间 | maxLifetime | maxEvictableIdleTimeMillis | 1800000ms(30分钟) |
你可能会问,为什么最大连接数要按CPU核心数来算?嗯,这里有个误区。很多人觉得连接数越多越好,其实不然。连接数太多,数据库CPU上下文切换反而更频繁,性能会下降。我在项目中遇到过,把最大连接数从200调到50,吞吐量反而提升了30%。
2.2 HikariCP配置实战
HikariCP现在几乎是Spring Boot的默认连接池了。它轻量、快,但参数调不好照样翻车。
# application.yml 配置示例
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
connection-test-query: SELECT 1
validation-timeout: 5000
leak-detection-threshold: 60000
我的小技巧:leak-detection-threshold 这个参数一定要设。设成60秒,如果某个连接被占用超过60秒,HikariCP就会打印警告日志。我曾经靠这个参数抓到一个慢SQL,那个SQL跑了45秒,把整个连接池都堵死了。
2.3 Druid配置实战
Druid在监控方面比HikariCP强很多。如果你需要详细的SQL执行统计,Druid是不二之选。
# Druid配置示例
spring:
datasource:
druid:
initial-size: 5
max-active: 20
min-idle: 5
max-wait: 30000
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,log4j2
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
注意:test-on-borrow 和 test-on-return 这两个参数,我建议都设成false。为什么?因为每次借出和归还连接都做校验,性能损耗太大。用 test-while-idle 就够了,它会在空闲时异步检测连接有效性。
2.4 连接泄漏检测
连接泄漏是MES系统最常见的坑之一。说白了就是代码里拿了连接没归还,时间长了连接池就枯竭了。
我曾经在一个MES项目里,生产环境每隔3小时就报「无法获取连接」的错误。查了两天才发现,是某个业务逻辑里try-catch之后,finally块忘了关闭PreparedStatement。嗯,就这一行代码,坑了全组人。
怎么检测?两个办法:
- 日志分析:开启连接池的泄漏检测日志,看哪个连接长时间没归还
- 监控工具:Druid自带监控页面,能看到活跃连接数和等待队列长度
避坑指南:我曾经在代码里用ThreadLocal缓存了数据库连接,想着能复用。结果线程池里的线程被回收时,连接没归还。这个坑我踩了整整一周。记住:永远不要在ThreadLocal里存数据库连接!
2.5 我踩过的三个大坑
做MES系统这么多年,连接池上栽的跟头不少。挑三个最典型的说说:
- 最大连接数设太大:一个MES产线有200台设备,我一开始把最大连接数设成了200。结果数据库CPU直接飙到100%,连接池里全是TIME_WAIT。后来压到30,反而稳了。
- 超时时间设太短:有次把connectionTimeout设成了5秒,结果MES系统里有个报表查询要跑8秒,频繁报超时。后来改成30秒,问题解决。但治标不治本,最后还是优化了那个SQL。
- 没开连接泄漏检测:这个最要命。系统运行了两个月,突然有一天所有接口都返回500。查了半天,是某个定时任务里连接没释放。从那以后,我每个项目都会强制开启泄漏检测。
2.6 性能对比与选型建议
直接说结论:
| 场景 | 推荐连接池 | 理由 |
|---|---|---|
| 高并发、低延迟 | HikariCP | 性能极致,启动快 |
| 需要SQL监控 | Druid | 监控功能强大,有防火墙 |
| 中小型MES系统 | HikariCP | 配置简单,够用 |
| 大型MES系统 | Druid | 需要慢SQL分析和告警 |
我个人习惯,新项目默认用HikariCP。如果客户要求有SQL审计功能,再切到Druid。你想想看,HikariCP的代码量只有Druid的十分之一,出问题的概率自然小很多。
2.7 知识体系图
下面这张图,把连接池优化的核心逻辑串起来了:
2.8 总结
连接池优化,说白了就是三个字:刚刚好。连接数刚刚好,超时刚刚好,检测刚刚好。别贪多,别图快,稳才是MES系统的第一要务。
最后送大家一句话:连接池的问题,90%都是代码没写好,10%才是配置没调对。先把代码写干净,再来调参数,顺序别搞反了。