多线程直接new Connection会导致连接数暴涨、端口耗尽、数据库拒绝连接;根本原因是连接是重量级资源且数据库有最大连接数限制;必须用连接池管理并正确关闭。
多线程直接 new Connection 会出什么问题
Java 多线程环境下,如果每个线程都调用 DriverManager.getConnection() 创建新连接,会出现连接数暴涨、TCP 端口耗尽、数据库拒绝连接(java.sql.SQLNonTransientConnectionException: Could not create connection)等问题。根本原因是数据库连接是重量级资源,创建/销毁开销大,且数据库服务端有最大连接数限制(如 MySQL 默认 max_connections=151)。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 禁止在多线程中手动
new Connection或反复调用getConnection() - 必须使用连接池(如 HikariCP、Druid、Apache DBCP2),由池统一管理生命周期
- 连接获取后务必在
try-with-resources或finally块中调用connection.close()—— 这里 close 实际是归还给池,不是真关闭
HikariCP 并发参数怎么设才不拖垮数据库
HikariCP 的核心并发控制参数只有两个:最大连接数 maximumPoolSize 和最小空闲连接数 minimumIdle。设得太大,数据库扛不住;设得太小,线程阻塞排队,吞吐上不去。关键不是拍脑袋,而是结合业务真实负载定。
实操建议:
立即学习“Java免费学习笔记(深入)”;
-
maximumPoolSize初始值可设为数据库max_connections * 0.8(留余量),再根据压测时的pool usage指标动态调优 -
minimumIdle建议与maximumPoolSize相同(即常驻连接),避免高并发时频繁创建连接;若连接空闲成本高(如跨机房),可设为maximumPoolSize / 2 - 务必开启
leakDetectionThreshold(如 60000ms),防止 Connection 忘记 close 导致连接泄漏 - 避免设置
connectionTimeout过长(默认 30s),否则线程会长时间卡在获取连接上
事务边界和 Connection 绑定怎么不出错
多线程下,一个 Connection 不能跨线程复用,而 Spring 的 @Transactional 默认基于 ThreadLocal 绑定当前线程的 Connection。如果手动起新线程(如 CompletableFuture.supplyAsync()),事务就失效了,且可能拿到不同连接,造成数据不一致或死锁。