2009-09-17 25 views
6

我们使用Spring SimpleJdbcCall调用Oracle中返回游标的存储过程。它看起来像SimpleJdbcCall没有关闭游标,并在一段时间后超过了最大打开游标。ORA-01000:使用Spring时超出最大打开游标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()。如果我在旧代码中注释掉那行,那么在加载测试后,我们会得到相同的数据库异常。

+3

请张贴一些代码,显示您如何使用SimpleJdbcCall。这很可能不是Spring中的错误,更可能是您使用它的方式,特别是考虑到Oracle处理结果集的非标准方式。 – skaffman 2009-09-17 08:55:32

+1

+1与skaffman。如果你找不到问题,可以尝试构建一个坚如磐石的测试用例,以在http://jira.springframework.org/上报告错误。 – 2009-09-17 15:02:27

回答

7

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

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

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

+5

我希望你报告这个,如果你认为它是一个错误:) – 2009-11-04 23:02:30

1

我可以向你保证它不是Spring。我从事的是2005年推出的Spring 1.x应用程序,并且自此以后就没有泄露过连接。 (WebLogic 9.,JDK 5)。你没有正确地关闭你的资源。

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

-3

的解决方案是不是在春天,但在甲骨文:您需要将OPEN_CURSORS初始化参数设置为某个值高于默认的50

甲骨文 - 至少-8I的,也许它已经改变 - - 将重新解析JDBC PreparedStatement对象,除非将它们保留为打开状态。这很昂贵,而且大多数人最终都会维持一个固定的重新提交的开放语句池。

(采取快速浏览一下10i的文档,他们明确指出OCI驱动程序将缓存的PreparedStatement,所以我假设本地驱动程序还是重新创建它们每次)

+2

这是资源泄漏,资源泄漏的解决方案是停止漏水,不加水。 – 2012-06-27 01:27:23

+1

@Andrew - 感谢您的评价以及您的downvote。但是,自从20世纪90年代初期与甲骨文合作以来,我坚持我的回答。开箱即用,其配置不适合复杂的应用程序。而且,OP使用的是Spring,它在清理后非常好。 OP仍然有可能在某处写入了资源泄漏,但与他/她进行明确的连接管理相比,其可能性要低得多。 – kdgregory 2012-06-30 12:12:30

+0

重读所有帖子,我发现OP在我的回复后两个月发布了接受的答案,表明它实际上是Spring的资源泄漏。然而,假设所谓的泄漏是Spring试图缓存元数据,我会参考我的第二段,并且仍然支持这个答案。 – kdgregory 2012-06-30 12:15:52

-2

甲骨文OPEN_CURSORS是关键好吗。我们有一个全天候运行的小型24x7应用程序,只有一些显然是开放的游标。直到我们将OPEN_CURSORS初始化值设置为> 300时,我们有间歇性的最大打开游标错误。

+4

这是资源泄漏,资源泄漏的解决方案是停止泄漏,不添加更多水。 – 2012-06-27 01:27:34

2

只需谨慎地将OPEN_CURSORS设置为更高和更高的值,因为有开销,并且它可能只是对实际问题/错误你的代码。

我没有与这个弹簧侧的经验,但在一个应用程序,我们有许多问题与ORA-01000错误的工作,并不断调整OPEN_CURSORS刚才提出的问题消失了一小会儿......

3

嗯,我在阅读BLOB时遇到了这个问题。主要原因是我也在更新表,并且包含update语句的Statement没有自动关闭。讨厌的cursorleak吃所有免费的游标。在显式调用statement.close()之后,错误消失。

道德 - 总是关闭所有的东西,配置语句后不要靠自动关闭。

相关问题