示例代码:
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吗?或者在后续循环中重用它们会释放先前循环中使用的内存/资源吗?
答案 0 :(得分:25)
结果集和(准备好的)语句的行为在Java API中明确记录。我建议您阅读实际文档(和JDBC规范)以获取详细信息。
Statement
API说:
默认情况下,每个
ResultSet
对象只能同时打开一个Statement
个对象。因此,如果一个ResultSet
对象的读取与另一个Statement
对象的读取交错,则每个对象必须由不同的Statement
对象生成。ResultSet
界面中的所有执行方法都会隐式关闭一个规则的当前aStmt.executeQuery()
对象(如果存在开放的对象)。
(强调我的)。
在您的特定代码中,当您致电ResultSet
时,驱动程序会隐式关闭分配给aRset
的旧ResultSet
。也就是说,最好自己明确地关闭它(或者使用Java 7 try-with-resources),以防止你忘记在循环的最后一次迭代中关闭PreparedStatement
。
现在到close()
:当您准备语句时(通常,实现可能会有所不同),查询将被发送到服务器进行编译。在执行时,将特定执行的参数发送到服务器。在aStmt
上调用ResultSet
会导致准备好的语句在服务器上被释放,显然不你想要的是什么,因为你想要重新使用不同的语句参数的值。
所以简而言之
ResultSet
(除了最后创建的PreparedStatement
),但最好明确地执行此操作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
}
}
}
。使用try-with-resources是消除这些问题的一部分混淆的一种方法,因为您的代码在完成后会自动释放资源(在使用范围的最后):
{{1}}
在这段代码的末尾,所有JDBC资源都被正确关闭(按正确顺序,即使发生异常等)
答案 1 :(得分:2)
不,您可能无法关闭ResultSet
循环中的Statement
和while
。
您必须在循环后关闭它们。
此外,如果您想重复使用PreparedStatement
,那么在您准备好处理之前,您可能无法关闭它。
最佳规则是在创建的同一块中关闭这些资源。在您的情况下,最好的办法是在捕获finally
后关闭SQLException
块中的资源。
E.g。
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 with resources。
答案 2 :(得分:0)
PreparedStatement API:预编译SQL语句并将其存储在PreparedStatement对象中。然后,可以使用此对象多次有效地执行此语句。
但是你不能重用ResultSet对象。第二次创建新的ResultSet时,在PreparedStatement对象上调用executeQuery时,如果不关闭以前的ResultSet,则可能会导致资源泄漏。