关闭连接和语句(finally)

10

在finally块中,哪种写法更好:

finally {
        try {
            con.close();
            stat.close();
        } catch (SQLException sqlee) {
            sqlee.printStackTrace();
        }
    }

或者:

finally {
        try {
            if (con != null) {
                con.close();
            }
            if (stat != null) {
                stat.close();
            }
        } catch (SQLException sqlee) {
            sqlee.printStackTrace();
        }
    }

嗯,因为第一个会抛出 NPE(NullPointerException)…… - Brian Roach
在关闭连接之前,您应该关闭语句。 - Mark Rotteveel
@MarkRotteveel 很好的笔记,你能告诉我们为什么吗? - Sajad
1
@Sajjad,因为语句是从连接创建的。在技术上正确实现的JDBC驱动程序将在关闭连接时关闭语句,但如果您不想依赖于此,您应该先关闭语句。 - Mark Rotteveel
5个回答

20
更好的使用方式是第二种,因为如果在初始化constat时抛出异常,它们将不会被初始化,并可能保持初始化为null。在这种情况下,使用第一段代码将抛出NullPointerException
另外,如果您已经使用Java 7,则应考虑使用try-with-resources,它会自动关闭资源。从链接的教程中可以看到:

try-with-resources语句确保在语句结束时关闭每个资源。任何实现java.lang.AutoCloseable接口的对象,包括所有实现java.io.Closeable接口的对象,都可以用作资源。


@Sajjad。点击答案中的链接。那是关于try-with-resources的Oracle教程。你可以仔细阅读它。 - Rohit Jain
好的,我们可以说这个try-with-resources比旧方法更简单吗?因为异常类型的规范是自动的,不需要捕获块吗? - Sajad
@Sajjad。从某种意义上说,这更简单,因为您不必担心关闭您正在使用的任何资源。但是您仍然需要提供一个catch块。 - Rohit Jain
@Sajjad。在教程中有一个ConnectionStatement的示例,你可以使用它。 - Rohit Jain

7

从Java 7开始,您不需要再使用finally块来关闭Connection或Statement对象。相反,您可以使用名为“try-with-resources”的新功能。

首先,您可以使用try-catch块的新语法声明Connection和Statament对象,如下所示:

try(Connection con =  DriverManager.getConnection(database-url, user, password); Statement st = conn.createStatement()) {

 //your stuffs here
} catch (SQLException e) {
   e.printStackTrace();
}    

这样做,你就不需要担心在 finally 块中显式关闭与数据库的链接,因为 jvm 会替你完成这项操作。
祝编码愉快....

6

它们都不够好。使用这个:

public static void closeQuietly(AutoCloseable ... closeables) {
    for (AutoCloseable c : closeables) {
        if (c != null) {
            try {
                c.close();
            } catch (Exception e) {
                // log or ignore, we can't do anything about it really
            }
        }
    }
}

可以像这样调用:closeQuietly(stat, con);

或者使用Java 7的try-with-resource

    List<String> results = new ArrayList<>();
    try (Statement statement = conn.createStatement();
         ResultSet rs = statement.executeQuery(query)) {

        int numberOfColumns = getColumnCount(rs);
        while (rs.next()) {
            int i = 1;
            while (i <= numberOfColumns) {
                results.add(rs.getString(i++));
            }
        }
    }

非常不错的方法!但我仍然认为一个finally块(将每个c = null;设置)是可取的。 - Barranka
除非作用域很长,否则不应手动将字段/变量设置为null以“通知”GC。在上面的示例中,我们谈论的是一毫秒或更短的时间,收益很低(如果有的话)。 - Xabster
我对这个问题做了太广泛的回答。在上面的例子中,连接(Connection)和语句(Statement)的原始引用仍然存在于该方法之外(调用该方法的人仍然拥有原始引用),我们只是将传递给我们方法的引用副本设为null。 - Xabster

0
如果有可能其中一个是null,你必须检查它。如果不存在这种可能性,则没有必要检查它。
此外,通过省略某些单语句括号,可以使您的代码更易读:
finally {
    try {
        if (con != null)
            con.close();

        if (stat != null)
            stat.close();

    } catch (SQLException sqlee) {
        sqlee.printStackTrace();
    }
}

2
虽然这是个人偏好,但我真的不喜欢省略单语句的括号。特别是当它们包含更多没有括号的单语句时。我发现这样的代码更难读懂,而且如果缩进不一致,可读性会进一步降低。 - Muel

0
我会选择第二个选项,但是添加第二个嵌套的finally块,以确保constat对象都被标记为垃圾回收。
finally {
    try {
        if(con != null)
            con.close();
        if(stat != null)
            stat.close();
    } catch(SQLException sqlee) {
        sqlee.printStackTrace();
    } finally {  // Just to make sure that both con and stat are "garbage collected"
        con = null;
        stat = null;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接