【问题标题】:Does reusing a Statement and Resultset release resources from its previous usage? Or do I have to explicitly close them before reuse?重用语句和结果集是否会释放其先前使用的资源?还是我必须在重用之前明确关闭它们?
【发布时间】:2013-07-10 16:03:40
【问题描述】:

示例代码:

        aStmt = aConn.prepareStatement(aQuery);
        aRset = aStmt.executeQuery(cQuery);

        while (cRset.next()) {
            //stuff to determine value of parm1

            aStmt.setString(1, parm1);                
            aRset = aStmt.executeQuery(); 

            //more stuff
        }

在 while 语句中的每个循环之后,我是否必须关闭 aStmt 和 aRset?或者在后续循环中重用它们会释放之前循环使用的内存/资源?

【问题讨论】:

    标签: java jdbc resultset


    【解决方案1】:

    Java API 中明确记录了结果集和(准备好的)语句的行为。我建议您阅读实际文档(和 JDBC 规范)以获取详细信息。

    Statement API 说:

    默认情况下,每个Statement 对象只能同时打开一个ResultSet 对象。因此,如果一个ResultSet 对象的读取与另一个ResultSet 对象的读取交错,则每个对象都必须由不同的Statement 对象生成。 Statement 接口中的所有执行方法都会隐式关闭语句的当前ResultSet 对象(如果存在打开的对象)。

    (强调我的)。

    在您的特定代码中,当您调用aStmt.executeQuery() 时,分配给aRset 的旧ResultSet 会被驱动程序隐式关闭。也就是说,最好自己显式关闭它(或使用 Java 7 try-with-resources),以防止您忘记在循环的最后一次迭代中关闭 ResultSet

    现在到PreparedStatement:当你准备一个语句时(通常,实现可能会有所不同),查询被发送到服务器进行编译。在执行时,该特定执行的参数被发送到服务器。在aStmt 上调用close() 将导致准备好的语句在服务器上被释放,这显然是不是你想要的,因为你想重新使用具有不同参数值的语句.

    总之

    1. 在这里关闭ResultSet 在技术上不是必需的(除了最后创建的ResultSet),但最好明确地这样做
    2. 您只应在完成后关闭PreparedStatement

    使用try-with-resources 是消除对这些问题的部分混淆的一种方法,因为您的代码会在使用完毕后自动释放资源(在使用范围结束时):

    try (
        ResultSet cRset = cStmt.executeQuery(cQuery);
        PreparedStatement aStmt = aConn.prepareStatement(aQuery);
    ) {
        while (cRset.next()) {
            //stuff to determine value of parm1
    
            aStmt.setString(1, parm1);                
            try (ResultSet aRset = aStmt.executeQuery()) {
                //more stuff
            }
        }
    }
    

    在这段代码的最后,所有 JDBC 资源都被正确关闭(以正确的顺序,即使发生异常等)

    【讨论】:

    • 实际上,对于最后创建的 ResultSet(所有其他未关闭的资源),我有一个方法可以在程序结束时关闭所有内容。考虑到这一点,我的逻辑可以保持原样吗?
    • @heisenbergman 您应该在不再需要资源时立即关闭它们。让它们保持打开状态可能会增加应用程序和数据库中的内存使用量。
    【解决方案2】:

    不,您不能关闭while 循环内的ResultSetStatement

    你必须在循环结束后关闭它们。

    此外,如果您想重复使用 PreparedStatement,那么在您准备好处理之前,您可能不会关闭它。

    最好的规则是在创建它们的同一块中关闭这些资源。在您的情况下,最好的办法是在捕获 SQLException 之后关闭 finally 块中的资源。

    例如

    try {
        aStmt = aConn.prepareStatement(aQuery);
        cRset = cStmt.executeQuery(cQuery);
    
        while (cRset.next()) {
            //stuff to determine value of parm1
    
            aStmt.setString(1, parm1);
            try {
                aRset = aStmt.executeQuery();
            } finally {
                aRset.close();
            }
    
            //more stuff
        }
    } catch (SQLException ex) {
        // Do error handling
    } finally {
        // Close Resultset
    }
    

    在 Java 7 中,您可以对资源使用 try。

    【讨论】:

      【解决方案3】:

      PreparedStatement API:SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用该对象多次有效地执行该语句。

      但是您不能重用 ResultSet 对象。当您在第二次创建新的 ResultSet 时对 PreparedStatement 对象调用 executeQuery 时,如果您不关闭之前的 ResultSet,您将面临资源泄漏的风险。

      【讨论】:

      • JDBC 规范要求驱动程序关闭旧的ResultSet,如果从同一个Statement 对象创建新的@。
      猜你喜欢
      • 2012-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 2014-07-30
      • 1970-01-01
      • 1970-01-01
      • 2017-05-24
      相关资源
      最近更新 更多