Spring+Tomcat+PostgreSQL连接槽耗尽问题求助(已配Tomcat连接池)
解决PostgreSQL连接槽耗尽问题(FATAL: remaining connection slots are reserved...)
看起来你遇到了PostgreSQL连接数耗尽的典型问题——数据库的总连接数已经被占满,剩下的连接槽预留给超级用户使用,导致普通应用用户无法建立新连接。结合你的技术栈(Spring 4.1 + Tomcat 8.5.30 + PostgreSQL 9.6)和已配置的Tomcat JDBC连接池,我给你几个具体的排查和解决方向:
1. 先确认数据库端的连接情况
首先要搞清楚数据库的总连接上限和当前实际占用数,这是定位问题的基础:
- 登录PostgreSQL执行以下SQL:
-- 查看数据库允许的最大连接数 SHOW max_connections; -- 查看当前所有活跃连接数 SELECT count(*) FROM pg_stat_activity; -- 查看连接来源(IP/应用),找到占用最多的对象 SELECT client_addr, application_name, count(*) FROM pg_stat_activity WHERE state = 'active' GROUP BY client_addr, application_name;
默认PostgreSQL的max_connections是100,superuser_reserved_connections(留给超级用户的预留连接)默认是3。如果你的Tomcat连接池maxActive=70,再加上其他可能的连接(比如其他应用、数据库工具、maven构建过程中的临时连接),很容易接近或达到100的上限。
2. 检查Tomcat连接池的配置有效性和连接泄漏
你已经配置了Tomcat JDBC连接池的removeAbandoned、logAbandoned等参数,接下来要验证这些配置是否真的在工作:
- 查看Tomcat的日志文件,找有没有包含
AbandonedConnection关键字的日志。如果有,日志会告诉你哪个线程、哪个代码位置没有正确释放连接——这就是连接泄漏的源头。 - 确认连接池的
maxActive设置是否合理:建议将maxActive调整为max_connections - superuser_reserved_connections - 其他固定连接数,比如如果数据库max_connections是100,那maxActive设为80左右比较安全,避免占满所有连接槽。 - 检查
minEvictableIdleTimeMillis和testWhileIdle的配合:你的配置是30秒空闲回收+空闲时验证,这个没问题,但可以通过JMX查看连接池的统计数据(比如空闲连接数、活跃连接数的变化),确认Tomcat是否在定期回收空闲连接。
3. 排查maven install时的连接累积问题
连续两次maven install出现问题,大概率是旧应用进程没有完全退出,导致旧的连接池还在占用数据库连接:
- 执行
ps aux | grep java(Linux)或打开任务管理器(Windows),看看有没有多余的Tomcat/Java进程。如果有,手动杀掉这些进程,释放它们占用的数据库连接。 - 检查Tomcat的热部署配置:如果开启了热部署,确保应用卸载时能正确销毁DataSource,释放连接池中的所有连接。如果是Spring配置的DataSource,可以添加
destroy-method="close"到bean定义,确保容器销毁时关闭连接池。
4. 代码层面检查连接泄漏
即使使用了连接池,代码中的不当操作也会导致连接泄漏:
- 确保所有数据库操作都使用try-with-resources语法(Java 7+支持),自动关闭Connection、Statement、ResultSet:
try (Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.prepareStatement("SELECT * FROM table"); ResultSet rs = stmt.executeQuery()) { // 处理查询结果 } catch (SQLException e) { // 异常处理 }
- 如果你用的是Spring的JdbcTemplate,它会自动管理连接的获取和释放,尽量避免手动获取Connection的操作,减少泄漏风险。
5. 临时缓解(治标不治本)
如果需要快速恢复服务,可以临时调大PostgreSQL的max_connections参数:
- 修改
postgresql.conf文件中的max_connections值(比如改为200),然后重启PostgreSQL服务。但这只是临时解决,一定要找到连接泄漏的根本原因,否则问题还会复发。
内容的提问来源于stack exchange,提问作者ines farhani




