关闭资源的顺序

Posted

技术标签:

【中文标题】关闭资源的顺序【英文标题】:Order in closing resources 【发布时间】:2013-05-28 20:06:17 【问题描述】:

我应该在连接之前关闭语句吗?和声明之前的结果集? 还是完全相反?

Connection conn = null;
Statement st = null;
Resultset rs = null;

try 
    // Do stuff

 catch (SQLException e) 
    // Do stuff

finally 
    if (rs != null) rs.close();
    if (st != null) st.close();
    if (conn != null) conn.close();         

或者

Connection conn = null;
Statement st = null;
Resultset rs = null;

try 
    // Do stuff

 catch (SQLException e) 
    // Do stuff

finally 
    if (conn != null) conn.close();         
    if (st != null) st.close();
    if (rs != null) rs.close();

【问题讨论】:

规则很简单:按打开的相反顺序关闭。关闭连接后,关闭语句将毫无意义。 注意:void close() 抛出 SQLException,每个 close() 必须在自己的 try/catch 中 一般情况下,您应该以 LIFO 的方式关闭资源——后进先出。因此,您打开的第一件事(连接)应该是最后关闭的。第一种方法更有意义。 理想情况下,当您关闭Connection 时,兼容的JDBC 驱动程序、连接池等将关闭ResultSetStatement 等;但不幸的是,现实情况并非总是如此。 @Aubin 或将关闭包装在一个方法中。如果您的程序正在终止并且它没有关闭数据库连接,这没什么大不了的,因为当 JVM 死掉时,该资源也会死掉。如果您的程序需要继续运行,这是一个问题,因为您泄露的资源将继续存在。 【参考方案1】:

关闭结果集,然后是语句,然后是连接。

换句话说,按照后进先出的原则关闭所有内容。

【讨论】:

AKA,也称为Stack @SnakeDoc AKA 也称为也称为。 @Pescis 我必须达到最低炭化量;-P 虽然这确实回答了问题,但它无助于 OP 成为更好的程序员,也无助于获得更多知识。 OP,看看 A.R.M. / Try-With-Resources 块用于在现代 Java (Java 7+) 中执行此操作的正确方法。 docs.oracle.com/javase/tutorial/essential/exceptions/…【参考方案2】:

您应该按照与打开顺序相反的顺序关闭资源(就好像这些资源在堆栈上一样)。

使用 Java 7 try-with-resources,理想的方法是:

try (
   Connection conn = somethingThatGetsAConnection();
   Statement st = conn.createStatement();
   Resultset rs = st.executeQuery("SELECT something");
) 
    // Do stuff

 catch (SQLException e) 
    // Do stuff

Java 会为你处理好它,它会以相反的顺序关闭资源。另见Oracle tutorial on try-with-resources:

请注意,资源的“关闭”方法是按其创建的相反顺序调用的。

您可以在文章 Better Resource Management with Java SE 7: Beyond Syntactic Sugar 中找到对 try-with-resources 的更深入了解

14.20.3 部分提到的 Java 7 的 Java 语言规范:

资源按从左到右的顺序初始化。如果资源初始化失败(即,其初始化表达式抛出异常),则到目前为止由try-with-resources 语句初始化的所有资源都将关闭。如果所有资源初始化成功,try 块将正常执行,然后关闭try-with-resources 语句的所有非空资源。

资源以与初始化相反的顺序关闭。仅当资源初始化为非空值时才关闭资源。关闭一个资源的异常不会阻止关闭其他资源。

这也可以看作是一个明确的迹象,表明 Java 语言设计者考虑以与分配规范相反的顺序关闭资源。

【讨论】:

@Aubin 你错了。也请从此答案中删除您的 -1 。 ARM 块顺序无关紧要,JVM 会处理它。这比 OP 预期的更好地回答了 OP 的问题。 @Aubin 添加了对相反顺序的简短提及,但我认为 *** 并不总是要回答确切的问题,而是要为实际问题提供更好的答案。 try-with-resources 通过消除实际思考的需要来解决问题。 好的,现在是的,我已经删除了我的反对票。对 JLS 的引用将很好地完成此答案。 @Aubin 更新了我的答案,尽管在我阅读 JLS 时它明确提到了一次关闭中的异常,但不会阻止另一次关闭:“关闭一个资源的异常不会防止关闭其他资源。”(当然这可能意味着您尝试关闭的特定资源尚未关闭,但在没有 try-with-resources 的情况下也会发生这种情况【参考方案3】:

ResultSetStatement,然后是Connection。 JDBC 连接和语句的黄金法则是以启动或打开的反向 顺序关闭。此外,ResultSet 依赖于Statement 的执行,Statement 依赖于Connection 实例。因此,关闭应按该顺序进行(ResultSet、Statement、Connection)。

【讨论】:

【参考方案4】:

第一个例子是正确的方法。任何其他订单的问题是关闭Statement 也会自动关闭任何底层ResultSetConnection 也可能发生同样的情况) - 所以您需要先关闭层次结构中最低的一个。

@aubin 指出,close() 方法可能会抛出 SQLException。解决这个问题的一个简单方法是使用 DBUtils closeQuietly() 方法来关闭它们——然后你甚至不需要空检查!

【讨论】:

【参考方案5】:

要以最小的努力解决这个问题,请尝试使用 Java 7 的新 A.R.M. (自动资源管理)块,也称为 Try-With-Resources。

try (Connection conn = null, Statement st = null, ResultSet rs = null)
    // Do stuff

 catch (SQLException e) 
    // Do stuff

没有丑陋的Finally 或担心正确的顺序,Java 会为您处理。

更多关于 ARM/Try-With-Resources 块的信息:http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

【讨论】:

关闭操作的顺序呢?这是问题,你不回答...... @Aubin 它更好地回答了他的问题。在 ARM 块中顺序无关紧要,发明了 ARM 块来解决这个确切的问题。请删除你的 -1 @SnakeDoc 在 ARM 中以分配的相反顺序调用关闭 @SnakeDoc 我正在阅读该教程,您还链接到其中明确提及它(请参阅我的回答中的引用)。 AFAIK 编译器实际上将 try-with-resources 转换为具有一些(复杂)异常处理的 finally 块;它只不过是语法糖。 在 try-with-resources 上也可以看到这个链接(尤其是最后的揭秘部分):oracle.com/technetwork/articles/java/…

以上是关于关闭资源的顺序的主要内容,如果未能解决你的问题,请参考以下文章

java程序中的流都要统统关闭吗?有没有先后顺序??

高效 告别996,开启java高效编程之门 4-3传统方式关闭流资源

高效 告别996,开启java高效编程之门 4-3传统方式关闭流资源

ORACLE DG 主备库开启与关闭顺序

Oracle 11gR2 RAC集群服务启动与关闭总结

具有依赖关系的 Windows 服务的关闭顺序 [关闭]