仅在finally块中关闭JDBC-Connections?

tom*_*189 5 java tomcat jdbc

为什么数据库连接经常在两个位置关闭,一次是在使用后直接关闭,其次是在finally块中使用null检查以防止它们被关闭两次.使用finally块是不够的?在每种情况下都要执行finally块.

这是Apache-Tomcat JNDI数据源HOW-TO的官方示例.他们指出,在任何情况下都必须关闭连接.我想知道为什么使用finally-block是不够的,因为主try {} -block结束时的close-commands似乎是redundent.

    Connection conn = null;
    Statement stmt = null; // Or PreparedStatement if needed
    ResultSet rs = null;
    try
    {
        conn = ... get connection from connection pool ...
        stmt = conn.createStatement("select ...");
        rs = stmt.executeQuery();
        ... iterate through the result set ...
        rs.close ();
        rs = null;
        stmt.close ();
        stmt = null;
        conn.close (); // Return to connection pool
        conn = null; // Make sure we don't close it twice
    }
    catch (SQLException e)
    {
        ... deal with errors ...
    }
    finally
    {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rs != null)
        {
            try
            {
                rs.close ();
            }
            catch (SQLException ignore)
            {
            }
            rs = null;
        }
        if (stmt != null)
        {
            try
            {
                stmt.close ();
            }
            catch (SQLException ignore)
            {
            }
            stmt = null;
        }
        if (conn != null)
        {
            try
            {
                conn.close ();
            }
            catch (SQLException ignore)
            {
            }
            conn = null;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我想写得更短:

    Connection conn = null;
    Statement stmt = null; // Or PreparedStatement if needed
    ResultSet rs = null;
    try
    {
        conn = ... get connection from connection pool ...
        stmt = conn.createStatement ("select ...");
        rs = stmt.executeQuery();
        ... iterate through the result set ...
    }
    catch (SQLException e)
    {
        // ... deal with errors ...
    }
    finally
    {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        try
        {
            if (rs != null)
                rs.close ();
            if (stmt != null)
                stmt.close ();
            if (conn != null)
                conn.close ();
        }
        catch (SQLException ignore)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 6

你有一个很好的问题 - 我也不理解"官方例子".最后块肯定够了.

然而,你的代码有更严重的缺陷,即如果rs.close()将抛出一个异常,你必须stmtconn泄漏出来,你想也忽略例外默默.这是你不应该做的事情.从Java 7开始,使用try-with-resources构造是首选方法,但如果你不能去那里,至少分别处理每个可能的异常(rs,stmt,conn),这样它们就不会导致彼此泄漏.

例如,Apache commons DbUtils 只为此目的而使用closeQuietly(),因为它曾经是一种常见的场景.我个人会去像Spring JDBCTemplate那样在幕后做这种事情的地方.

编辑:Oracle 在此解释了try-with-resources .简而言之,你会这样做:

try (Connection conn = yourCodeToGetConnection();
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(query)) {
    while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");

        System.out.println(coffeeName + ", " + supplierID + ", " + 
                               price + ", " + sales + ", " + total);
    }
} catch (SQLException ex) {
    // log, report or raise
}
Run Code Online (Sandbox Code Playgroud)

try-statement自动处理conn,stmtrs在所有情况下按顺序关闭(与您声明它们的相反顺序).您仍需要处理的可能异常.