最直接有效的办法是引入数据库连接池,预建连接供业务“借用归还”,避免每次新建关闭的高开销;推荐HikariCP、Druid或DBCP2,需合理配置maximumPoolSize、minimumIdle等参数,并配合DAO层统一获取、事务内复用连接及正确close(),再通过日志和监控验证效果。

最直接有效的办法是引入数据库连接池,彻底避免每次操作都新建和关闭连接。
用连接池代替手动开关连接
每次调用 DriverManager.getConnection() 都要经历 TCP 握手、身份认证、初始化会话等步骤,开销大且不可忽略。连接池在应用启动时就预建一批连接,业务需要时“借”一个,用完“还”回去,不销毁也不重建。
- 主流选择有 HikariCP(性能最优、推荐)、Druid(功能丰富、监控强)、DBCP2(老牌稳定)
- 以 HikariCP 为例:只需配置 URL、账号密码和最大连接数,
HikariDataSource.getConnection()返回的连接实际来自池中,close()只是归还,不是真关闭 - 避免在方法内写
sql.Open+defer conn.Close()这类直连逻辑,那是高并发下的性能陷阱
合理配置连接池参数
池子不是越大越好,参数配错反而拖慢系统。
- maximumPoolSize:设为数据库允许的最大连接数 × 0.8 左右,留余量给其他服务或后台任务
- minimumIdle:保持一定数量空闲连接(如 5~10),避免突发请求时临时创建的延迟
- connectionTimeout:获取连接超时建议设为 30 秒以内,防止线程长时间卡死
-
validationTimeout / keepaliveTime:开启连接有效性检测(如
SELECT 1),定期清理失效连接,避免拿到“假连接”报错
配合代码结构做轻量优化
连接池解决的是底层资源复用问题,上层代码也要配合,才能发挥最大效果。
立即学习“Java免费学习笔记(深入)”;
- DAO 层统一通过连接池获取连接,不要在 Service 或 Controller 层直接拿连接
- 一个业务操作尽量复用同一个连接(比如一次事务内多个 SQL),避免反复从池中取放
- 确保
try-with-resources或finally中正确调用close(),否则连接无法归还,池会逐渐枯竭 - 避免在循环里查单条数据,改用批处理(
PreparedStatement.addBatch())或一次性拉取后内存处理
验证是否真正生效
光配了池子不等于优化落地,得看真实行为。
- 打开连接池的 DEBUG 日志(如 HikariCP 的
com.zaxxer.hikari),观察“obtained connection”和“returned connection”是否高频出现,而不是“Created connection” - 监控数据库端的活跃连接数:未用池时可能随 QPS 线性飙升;用了池后应稳定在配置的 min~max 区间内
- 压测对比:同样接口,QPS 提升、平均响应时间下降、错误率(如连接超时)显著减少,就是起效了



















