使用Hibernate 3.6+C3P0连接池遭遇ORA-01000:超出最大打开游标数错误
我之前在项目里也碰到过几乎一模一样的问题,结合你的场景来看,核心原因就是连接池复用连接时,没有正确清理连接上绑定的游标资源——毕竟不用连接池时,连接关闭会自动释放所有关联资源,但连接池里的连接是被复用的,游标如果没及时清理就会一直累积,直到超过Oracle的open_cursors限制。
下面是我亲测有效的解决步骤,按优先级排序:
1. 先检查Hibernate的连接释放配置
确保Hibernate在事务结束后能正确释放连接相关资源,在hibernate.cfg.xml里添加或修改这个配置:
<property name="hibernate.connection.release_mode">auto</property>
这个参数会让Hibernate自动在合适的时机(比如事务提交/回滚后)释放连接资源,避免Session一直持有连接不清理游标。另外要确认代码里的Session和Transaction都正确关闭了——比如每次用完Session都要调用session.close(),事务不管成功失败都要执行commit()或rollback()。
2. 给C3P0添加强制清理资源的配置
你用的c3p0-0.9.2-pre1是预览版,本身就有不少资源泄漏的已知问题,加上这些配置可以强制清理连接上的Statement(游标就是Statement关联的资源):
<!-- 禁用Statement缓存,每次用完都直接关闭 --> <property name="hibernate.c3p0.max_statements">0</property> <!-- 强制回收300秒未归还的连接,避免资源长期占用 --> <property name="hibernate.c3p0.unreturnedConnectionTimeout">300</property> <!-- 开启调试,打印未归还连接的堆栈,方便排查泄漏点 --> <property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">true</property> <!-- 每隔300秒检查空闲连接的有效性 --> <property name="hibernate.c3p0.idle_test_period">300</property>
max_statements设为0是关键,因为C3P0的Statement缓存如果配置不当,很容易导致游标泄漏;调试参数可以帮你定位到代码里哪里没正确归还连接,非常有用。
3. 升级C3P0到稳定版本
0.9.2-pre1的bug真的不少,建议直接升级到0.9.5.x系列的稳定版(比如0.9.5.5),这个版本修复了大量连接和资源管理的问题,兼容性也更好,很多时候升级后游标问题直接就消失了。
4. 临时调大Oracle的open_cursors参数(应急用)
如果上面的配置还没生效,或者需要先缓解问题,可以临时调大Oracle的游标限制:
ALTER SYSTEM SET open_cursors = 500 SCOPE=BOTH;
注意这只是治标,不能从根本解决资源泄漏的问题,还是要结合前面的步骤处理。
5. 排查代码中的手动JDBC操作
如果代码里有用session.doWork()或者直接获取JDBC连接做操作的情况,一定要确保Statement和ResultSet在finally块里关闭:
session.doWork(connection -> { Statement stmt = null; ResultSet rs = null; try { stmt = connection.createStatement(); rs = stmt.executeQuery("SELECT ..."); // 处理业务逻辑 } finally { // 必须按顺序关闭:ResultSet -> Statement if (rs != null) rs.close(); if (stmt != null) stmt.close(); } });
手动操作JDBC最容易漏关资源,这也是游标泄漏的常见原因之一。
内容的提问来源于stack exchange,提问作者SandeepMunday

