ORA-01000:使用Spring SimpleJDBCCall时超出最大打开游标数

我们使用Spring SimpleJdbcCall来调用返回游标的Oracle中的存储过程。 看起来SimpleJdbcCall没有关闭游标,一段时间后超出了最大打开游标。

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

在论坛上有一些其他人经历过这个,但似乎没有答案。 它看起来像我在spring / oracle支持中的一个bug。

这个bug很关键,可能影响我们将来使用Spring JDBC。

有没有人遇到过修复 – 要么将问题跟踪到Spring代码,要么找到避免问题的解决方法?

我们正在使用Spring 2.5.6。

这是使用SimpleJdbcCall的代码的新版本,它似乎无法正确关闭proc通过游标返回的结果集:

 ... SimpleJdbcCall call = new SimpleJdbcCall(dataSource); Map params = new HashMap(); params.put("remote_user", session.getAttribute("cas_username") ); Map result = call .withSchemaName("urs") .withCatalogName("ursWeb") .withProcedureName("get_roles") .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper() ) .execute(params); List roles = (List)result.get("rolesCur") 

不使用Spring JDBC的旧版本代码没有此问题:

 oracleConnection = dataSource.getConnection(); callable = oracleConnection.prepareCall( "{ call urs.ursweb.get_roles(?, ?) }" ); callable.setString(1, (String)session.getAttribute("cas_username")); callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); callable.execute(); ResultSet rset = (ResultSet)callable.getObject(2); ... do stuff with the result set if (rset != null) rset.close(); // Explicitly close the resultset if (callable != null) callable.close(); //Close the callable if (oracleConnection != null) oracleConnection.close(); //Close the connection 

看起来Spring JDBC不会调用rset.close()。 如果我在旧代码中注释掉该行,那么在加载测试之后我们会得到相同的数据库exception。

经过多次测试后我们解决了这个问题。 它是我们如何使用spring框架和oracle客户端以及oracle DB的组合。 我们正在创建新的SimpleJDBCCalls,它们使用oracle JDBC客户端的元数据调用,这些调用作为游标返回,而这些游标未被关闭和清理。 我认为这是Spring JDBC框架中一个如何调用元数据然后不关闭游标的错误。 Spring应该从光标中复制元数据并正确关闭它。 我没有打算用spring打开jira问题,因为如果你使用最佳实践,那么bug就不会被展示出来。

调整OPEN_CURSORS或任何其他参数是解决此问题的错误方法,只是延迟它出现。

我们通过将SimpleJDBCCall移动到单个DAO中来解决它/修复它,因此我们调用的每个oracle proc只打开一个游标。 这些游标在应用程序的生命周期内是开放的 – 我认为这是一个错误。 只要OPEN_CURSORS大于SimpleJDBCCall对象的数量,就不会有麻烦。

好吧,当我读BLOB时,我遇到了这个问题。 主要原因是我也在更新表,并且包含update子句的Statement没有自动关闭。 令人讨厌的光标漏掉了所有免费游标。 显式调用statement.close()后,错误消失。

道德 – 总是关闭一切 ,处理完声明后不依赖自动关闭。

请注意将OPEN_CURSORS设置为越来越高的值,因为存在开销,它可能只是对代码中的实际问题/错误进行频带辅助。

我没有使用Spring方面的经验,但是在一个应用程序上工作,我们遇到ORA-01000错误的许多问题,并且不断调整OPEN_CURSORS只是让问题消失了一段时间……

我可以向你保证,这不是spring。 我曾在2005年上线的Spring 1.x应用程序上工作,并且从那时起就没有泄露连接。 (WebLogic 9.,JDK 5)。 您没有正确关闭资源。

你在使用连接池吗? 您正在部署哪个应用服务器? 哪个版本的Spring? 甲骨文? Java的? 请详细说明。

Oracle OPEN_CURSORS是关键。 我们有一个针对Oracle XE运行的小型24×7应用程序,只有几个明显开放的游标。 我们有间歇性的最大打开游标错误,直到我们将OPEN_CURSORS初始化值设置为> 300

解决方案不在Spring中,而是在Oracle中:您需要将OPEN_CURSORS初始化参数设置为高于默认值50的某个值。

Oracle – 至少从8i开始,或许它已经改变了 – 将重新解析JDBC PreparedStatement对象,除非你把它们打开。 这很昂贵,大多数人最终都会维护一个重新提交的固定语句池。

(快速浏览一下10i文档,他们明确指出OCI驱动程序会缓存PreparedStatements,所以我假设本机驱动程序每次都会重新创建它们)