19

示例代码:

        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?还是在后续循环中重用它们会释放先前循环中使用的内存/资源?

4

3 回答 3

26

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

StatementAPI 说:

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

(强调我的)。

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

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

所以简而言之

  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 资源都正确关闭(以正确的顺序,即使发生异常等)

于 2013-07-12T07:37:48.220 回答
2

不,您不能关闭循环内部的ResultSetand 。Statementwhile

您必须在循环后关闭它们。

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

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

例如

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。

于 2013-07-12T07:23:34.493 回答
0

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

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

于 2013-07-12T07:21:40.670 回答