据说在使用完JDBC资源后关闭所有资源是一个好习惯。但是如果我有下面的代码,是否有必要关闭Resultset和Statement?

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {};
    try { if (stmt != null) stmt.close(); } catch (Exception e) {};
    try { if (conn != null) conn.close(); } catch (Exception e) {};
}

问题是关闭连接是否有效,或者是否会留下一些可用的资源。


当前回答

使用Java 6表单,我认为最好在关闭之前检查它是否关闭(例如,如果一些连接池在其他线程中驱逐了连接)-例如一些网络问题-语句和结果集状态可以关闭。(这是不经常发生的,但我在Oracle和DBCP有这个问题)。我的模式是(在旧的Java语法中):

try {
    //...   
    return resp;
} finally {
    if (rs != null && !rs.isClosed()) {
        try {
            rs.close();
        } catch (Exception e2) { 
            log.warn("Cannot close resultset: " + e2.getMessage());
        }
    }
    if (stmt != null && !stmt.isClosed()) {
        try {
            stmt.close();
        } catch (Exception e2) {
            log.warn("Cannot close statement " + e2.getMessage()); 
        }
    }
    if (con != null && !conn.isClosed()) {
        try {
            con.close();
        } catch (Exception e2) {
            log.warn("Cannot close connection: " + e2.getMessage());
        }
    }
}

理论上,它不是100%完美的,因为在检查关闭状态和关闭本身之间,有一点空间来改变状态。在最坏的情况下,你很快就会得到警告。-但在长期运行的查询中,它小于状态变化的可能性。我们在“平均”负载(150个同时用户)的生产环境中使用了这个模式,我们没有遇到任何问题——所以从来没有看到警告消息。

其他回答

据我所知,在当前的JDBC中,resultset和语句实现了AutoCloseable接口。这意味着它们会在被摧毁或超出范围时自动关闭。

使用Java 6表单,我认为最好在关闭之前检查它是否关闭(例如,如果一些连接池在其他线程中驱逐了连接)-例如一些网络问题-语句和结果集状态可以关闭。(这是不经常发生的,但我在Oracle和DBCP有这个问题)。我的模式是(在旧的Java语法中):

try {
    //...   
    return resp;
} finally {
    if (rs != null && !rs.isClosed()) {
        try {
            rs.close();
        } catch (Exception e2) { 
            log.warn("Cannot close resultset: " + e2.getMessage());
        }
    }
    if (stmt != null && !stmt.isClosed()) {
        try {
            stmt.close();
        } catch (Exception e2) {
            log.warn("Cannot close statement " + e2.getMessage()); 
        }
    }
    if (con != null && !conn.isClosed()) {
        try {
            con.close();
        } catch (Exception e2) {
            log.warn("Cannot close connection: " + e2.getMessage());
        }
    }
}

理论上,它不是100%完美的,因为在检查关闭状态和关闭本身之间,有一点空间来改变状态。在最坏的情况下,你很快就会得到警告。-但在长期运行的查询中,它小于状态变化的可能性。我们在“平均”负载(150个同时用户)的生产环境中使用了这个模式,我们没有遇到任何问题——所以从来没有看到警告消息。

一些方便功能:

public static void silentCloseResultSets(Statement st) {
    try {
        while (!(!st.getMoreResults() && (st.getUpdateCount() == -1))) {}
    } catch (SQLException ignore) {}
}
public static void silentCloseResultSets(Statement ...statements) {
    for (Statement st: statements) silentCloseResultSets(st);
}

Java 1.7的try-with-resources语句使我们的工作变得更加简单。

try (Connection connection = dataSource.getConnection();
    Statement statement = connection.createStatement()) {
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do stuff with the result set.
    }
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do more stuff with the second result set.
    }
}

这个语法非常简洁和优雅。即使不能创建语句,连接也会被关闭。

正确和安全的关闭与JDBC this相关的资源的方法(摘自如何正确地关闭JDBC资源-每次):

Connection connection = dataSource.getConnection();
try {
    Statement statement = connection.createStatement();

    try {
        ResultSet resultSet = statement.executeQuery("some query");

        try {
            // Do stuff with the result set.
        } finally {
            resultSet.close();
        }
    } finally {
        statement.close();
    }
} finally {
    connection.close();
}