关闭ResultSet但不关闭PreparedStatement

时间:2015-03-10 16:25:10

标签: java oracle jdbc

如果关闭ResultSet,我可以预期哪种类型的资源泄漏,但PreparedStatement不会。它非常可疑,它可能会导致游标打开...

   PreparedStatement p = connection.prepareStatement(...);
    try {
      ResultSet r = p.executeQuery();
      try {
        while (r.next()) {
          ....
        }
      } finally {
        try {
          r.close();
        } catch (SQLException e) {
        // log this or something -- prevent these from masking original exception
        }
      }
    }

是Oracle 11g,jdbc 11.2.0.3

由于

Plz尝试回答我的问题,而不是专注于修复

2 个答案:

答案 0 :(得分:4)

  

如果关闭ResultSet,我可以期待什么类型的资源泄漏,但是   PreparedStatement不是吗?

泄漏将是最大的开放光标问题。

ORA-01000: maximum open cursors exceeded

如果超出最大打开游标数,则数据库将变为不可用,但已保留的游标除外。但是,大多数时候发生这种情况时,所使用的游标甚至都没有使用(在你的问题中就是这种情况)。


从java 7开始,处理此问题的最佳方法是使用try with ressourcesResultSetPreparedStatement都会实现AutoCloseable接口,这意味着它们将在不再需要时关闭。

如果您没有java 7,那么您需要在finally块中处理此问题,但请确保在关闭之前验证空值,否则如果从未初始化ressource,则可能会遇到NPE。 / p>

请注意,反向不会导致任何问题,因为关闭语句会自动关闭结果集。


请注意,您可以轻松地为应用程序添加更多游标,以减少超出最大值的可能性。

ALTER SYSTEM SET open_cursors = 400 SCOPE=BOTH;

但是,大多数情况下,如果遇到最大打开游标,这不应该是一个解决方案,因为它只会隐藏真正的问题。

答案 1 :(得分:1)

可能在Oracle中,您不会在数据库服务器端冒太多风险。准备好的语句在库缓存中共享,当语句没有被执行时,Oracle可以摆脱它。

但无论如何这是非常糟糕的习惯。在JDBC driver side.上发生的事情也值得怀疑 这是OCI文档的摘录,但我认为JDBC行为类似:

  

OCI中没有会话池的语句缓存

     

用户执行通常的OCI步骤进行登录。要求获得一个   session将有一个指定语句缓存是否的模式   已启用会话。最初语句缓存将为空。   开发人员将尝试使用缓存在缓存中查找语句   声明文本。如果该语句存在,则API将返回a   以前准备好的语句句柄,否则会重新返回   准备好的陈述句柄。

因此,当客户端使用PreparedStatement缓存时,Oracle似乎可以避免软解析。因此,当您不关闭PreparedStamement时,您可能会遇到此缓存问题。

注意:映射是RecultSet => “open cursor”,而PreparedStatement可能映射到Library缓存中的一个条目。对于Oracle,关闭ResultSet是至关重要的。

PS:相反,在Informix(PostgreSQL和其他RDBMS)上,执行计划不会被共享,并且每个会话进程/线程都拥有它自己的一组预准备语句。因此,当使用其他数据库时,您可能会遇到严重问题。