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

Bre*_*ood 8 java oracle spring jdbc

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

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 
Run Code Online (Sandbox Code Playgroud)

在论坛上有一些其他人经历过这个,但似乎没有答案.它看起来像我在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")
Run Code Online (Sandbox Code Playgroud)

不使用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
Run Code Online (Sandbox Code Playgroud)

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

Bre*_*ood 8

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

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

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

  • 如果你认为这是一个bug,我希望你报告这个:) (5认同)