重用语句和结果集是不是会释放其先前使用的资源?还是我必须在重用之前明确关闭它们?
Posted
技术标签:
【中文标题】重用语句和结果集是不是会释放其先前使用的资源?还是我必须在重用之前明确关闭它们?【英文标题】: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?或者在后续循环中重用它们会释放之前循环使用的内存/资源?
【问题讨论】:
【参考方案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()
将导致准备好的语句在服务器上被释放,这显然是不是你想要的,因为你想重新使用具有不同参数值的语句.
总之
-
在这里关闭
ResultSet
在技术上不是必需的(除了最后创建的ResultSet
),但最好明确地这样做
您只应在完成后关闭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
循环内的ResultSet
和Statement
。
你必须在循环结束后关闭它们。
此外,如果您想重复使用 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
对象创建新的@。以上是关于重用语句和结果集是不是会释放其先前使用的资源?还是我必须在重用之前明确关闭它们?的主要内容,如果未能解决你的问题,请参考以下文章
Beam Search生成的句子基本都一样,是不是有方法扩展生成句子的多样性?