连接池溢出导致模块挂起,表现为请求阻塞、线程卡在getconnection()、日志提示连接池耗尽;根本原因常是应用层连接泄漏或jdbc超时未设,而非数据库性能问题。

连接池溢出时模块挂起的典型现象
模块突然不响应、HTTP 请求卡住、线程堆栈里大量 getConnection() 阻塞、日志中反复出现 Connection pool exhausted 或 waiting for available connection —— 这不是数据库慢,是连接池已死锁式耗尽。关键点:挂起往往发生在应用层,而非数据库端;此时 SHOW PROCESSLIST 可能只看到几十个 Sleep 连接,但应用侧等待队列已堆积数百请求。
HikariCP 的 connection-timeout 不等于 JDBC socketTimeout
这是最常被忽略的致命错配。connection-timeout=30000 只控制从池子里“取连接”最多等 30 秒;它完全不管底层 TCP 连接是否能建得通。当数据库宕机或网络中断,JDBC 驱动(如 mssql-jdbc 或 mysql-connector-java)若没设 socketTimeout,会默认阻塞数分钟,导致每个等待线程都持有一个未完成的 PoolEntryCreator 实例,内存持续上涨,最终触发 OutOfMemoryError: Java heap space。
- MySQL 需在 JDBC URL 加
connectTimeout=5000&socketTimeout=10000 - SQL Server 必须加
socketTimeout=10000(loginTimeout不顶用) - PostgreSQL 对应参数是
connectTimeout=5&socketTimeout=10(单位秒) - Spring Boot 中不要只配
spring.datasource.hikari.connection-timeout,必须穿透到 URL 层
max-pool-size 设太高反而加速雪崩
盲目设 maximum-pool-size: 500 是自毁式配置。每个连接在 MySQL 端占 2–4MB 内存,500 个就是 1–2GB;更严重的是 MySQL 内部锁竞争激增,QPS 反而下降。HikariCP 官方推荐公式是 CPU核数 × 2 + 磁盘数,8 核单盘服务器建议值是 17,上限别超 100 —— 超过这个数,99% 是配置失当,不是并发真高。
- 先查真实并发:看
information_schema.processlist中Command='Query'的数量,通常不超过 20–30 - 把
maximum-pool-size降到 30–60,同时调低minimum-idle到 5–10,避免空转连接吃资源 - 配合
connection-test-query=SELECT 1(MySQL)或connection-test-query=SELECT 1 FROM DUAL(Oracle),确保空闲连接可验活
挂起后如何快速止血而不重启
等不到优雅降级?立刻执行这三步:
- 在数据库侧运行:
SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist WHERE command = 'Sleep' AND time > 60;,复制结果批量执行,清掉僵尸空闲连接 - 在应用侧 JMX 或 Actuator 端点(如
/actuator/hikaricp)调用softEvictConnections(),强制驱逐疑似失效连接 - 临时降低流量:通过网关限流(如 Spring Cloud Gateway 的
RequestRateLimiter)把并发压到池子容量的 70% 以下,给连接回收留出窗口
真正棘手的不是配置数字,而是连接泄漏本身——比如 try-with-resources 漏写、异步任务没 await、事务没 rollback 就 return。这些代码问题不修复,再好的池子也会被一点点抽干。











