Tomcat连接池未关闭连接?ORA游标超限及空闲会话无法释放求助
解决Tomcat连接池空闲Oracle会话未释放导致ORA游标超限的问题
我来分享下针对这个Tomcat连接池+Oracle场景下游标超限、空闲会话未释放问题的排查思路和解决方案,之前处理过类似的生产问题:
问题回顾
我们公司的第三方应用采用Tomcat连接池,近期遇到ORA游标超限的报错。为了释放空闲会话,我们配置了连接池的两个核心参数:
minEvictableIdleTimeMillis = 60000 # 空闲连接超过1分钟可被驱逐 timeBetweenEvictionRunsMillis = 60000 # 驱逐线程每分钟运行一次
但奇怪的是,即使完全没有业务流量,数据库里的空闲会话依然没有被正常回收。我们用以下SQL查询当前会话的游标使用和连接状态:
select a.value, s.username, s.sid, s.serial#, s.machine, to_char(cast(s.logon_time as date),'hh24:mi:ss') as activesince from v$sesstat a, v$statname b, v$session s where a.statistic# = b.statistic# and b.name = 'opened cursors current' and a.sid = s.sid and s.username is not null order by a.value desc;
可能的根因分析
- 连接有效性验证缺失:Tomcat连接池默认不会在驱逐前验证连接是否有效,如果连接已经和Oracle断开但池没检测到,驱逐线程不会主动回收这类连接
- minIdle参数冲突:如果
minIdle设置的数值高于当前空闲连接数,驱逐线程会维持最小空闲连接数,不会回收任何空闲连接 - 应用代码的连接/游标泄漏:代码中没有正确关闭
Connection、Statement或ResultSet,导致连接被占用,即使无流量也无法被池回收 - 驱逐线程未正常运行:可能因为Tomcat线程池阻塞、配置未正确加载等原因,驱逐线程没有按配置的频率执行
分步解决方案
1. 添加连接有效性验证配置
在Tomcat连接池的配置中加入以下参数,让驱逐线程能识别并回收失效连接:
testWhileIdle = true # 驱逐线程运行时验证空闲连接 validationQuery = SELECT 1 FROM DUAL # Oracle连接有效性检测语句 validationInterval = 30000 # 30秒内重复验证同一连接时跳过,避免频繁查询
2. 调整minIdle参数到合理值
如果minIdle设置过大(比如等于maxActive),空闲连接永远不会被回收。建议根据业务低峰期的流量设置:
minIdle = 5 # 维持5个空闲连接即可,可根据实际情况调整
确保当空闲连接数超过minIdle时,驱逐线程会自动回收多余的连接。
3. 排查并修复应用代码的连接泄漏
- 检查所有数据库操作代码,确保
Connection、Statement、ResultSet都在finally块中关闭,避免异常场景下的资源泄漏 - 开启Tomcat连接池的泄漏检测功能,定位泄漏点:
removeAbandoned = true # 自动回收废弃连接 removeAbandonedTimeout = 60 # 连接超过60秒未使用则标记为废弃 logAbandoned = true # 打印废弃连接的调用栈日志,方便定位代码
4. 确认驱逐线程的运行状态
- 调整Tomcat的日志级别到
INFO,查看日志中是否有org.apache.tomcat.jdbc.pool.Evictor相关的日志,确认驱逐线程是否每分钟启动一次 - 如果没有相关日志,检查连接池配置是否正确加载(比如是否配置在了正确的
Context.xml或应用配置文件中)
5. 手动验证修复效果
在无业务流量的情况下,等待超过minEvictableIdleTimeMillis的时间(比如1分钟),重新执行之前的SQL查询,观察会话数和游标数是否减少。如果还是没有变化,尝试重启应用确保配置生效。
内容的提问来源于stack exchange,提问作者Ele
相关产品推荐
相关产品推荐

