如何在while循环中正确处理Connection,ResultSet和Statement对象

时间:2013-07-08 14:39:36

标签: java jdbc

如果我有以下代码,这是关闭Connection,ResultSet和Statement对象的正确方法吗?我觉得close()的所有调用都应该在finally块中。

Connection con = null;
ResultSet rs = null;
Statement stmt = null;

try{
    //Code before the while loop 
    con = DriveManager.getConnection("Stuff");

    while(someBoolean){          

        stmt = con.createStatement();
        rs = stmt.executeQuery("SQL query");

        // do stuff with query results.

        if( rs != null){
               rs.close();
        }

        if( stmt != null){
               stmt.close();
        }

} //end while

    if( con != null ){
        con.close();
    }

catch (Exception e){
    //handle exception
}

4 个答案:

答案 0 :(得分:4)

是的,关闭资源应该在finally块中,因为无论可能引发异常,都应该关闭所有资源。

标准模式是:

Connection con = null;
ResultSet rs = null;
Statement stmt = null;

try {
    con = DriveManager.getConnection("Stuff");
    stmt = con.createStatement();
    rs = stmt.executeQuery("SQL query");
    // do stuff with query results
} catch (SQLException e) { // Don't catch Exception, catch what you expect
    // handle exception
} finally {
    // each close can itself explode, so wrap each in try catch
    try {
       if (rs != null)
           rs.close();
    } catch (SQLException ignore) {} // no point handling

    try {
       if (stmt != null)
           stmt.close();
    } catch (SQLException ignore) {} // no point handling

    try {
       if (con != null)
           con.close();
    } catch (SQLException ignore) {} // no point handling
}

虽然未能关闭其中一个资源可能意味着其他资源也会爆炸,但是,尝试关闭每个资源仍然是一个好习惯,因此在finally块中单独尝试捕获。

答案 1 :(得分:2)

您不需要在循环中创建Statement:您可以重复使用它。另外,使用Java 7 try-with-resources(tutorial),您不需要按照正确的顺序处理关闭的繁琐等等。

你可以这样做:

try (
    Connection con = DriverManager.getConnection("Stuff");
    Statement stmt = con.createStatement();
){
    while(someBoolean){          
        try (ResultSet rs = stmt.executeQuery("SQL query")) {
            // do stuff with query results.
        }
    } //end while
} catch (Exception e){
    //handle exception
}

正如您所看到的,它需要的检查和语句要少于自己管理它,而它确保以正确的顺序关闭资源,即使发生异常(即使在关闭其中一个资源时发生该异常)。例如,如果发生任何异常,您的旧代码无法关闭资源。

答案 2 :(得分:1)

在Java 7中,您可以使用try-with-resource语句:

try(Connection con = getConnection(url, username, password, "drivername");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
) {

  //statements
}catch(....){}

在Java 6中,您可以关闭finally块中的资源:

} finally {
   try { rs.close(); } catch (Exception e) {  }
   try { ps.close(); } catch (Exception e) {  }
   try { conn.close(); } catch (Exception e) {  }
}

您甚至可以使用帮助程序类来关闭连接。 Apache Commons DbUtils有一个DbUtils类。

} finally {
    DbUtil.closeQuietly(rs);
    DbUtil.closeQuietly(ps);
    DbUtil.closeQuietly(conn);
}

答案 3 :(得分:0)

我建议使用嵌套的try / catch块,每个资源

    final Connection conn = DriverManager.getConnection(jdbcUrl, jdbcUser,
            jdbcPassword);
    try {
        final Statement stmnt = conn.createStatement();
        try {
            final ResultSet rs = stmnt
                    .executeQuery("select * from pg_user");
            try {
                while (rs.next()) {
                    System.out.println(rs.getObject(1));
                }
            } finally {
                rs.close();
            }
        } finally {
            stmnt.close();
        }
    } finally {
        conn.close();
    }

每个finally子句中只有一个单个行。否则你必须将它包装在另一个try / catch中,以便在finally块中正确处理可能的异常。


一般来说,管理资源的这种模式(try / catch - 嵌套与否)会使代码混乱。摆脱一种方法是集中管理资源,并使用监听器/读取器。

因此,在库中,您可以定义Readerwith...方法:

interface ResultSetReader {
    void read(ResultSet rs) throws SQLException;
}

public static void withResultSet(final String query,
        final ResultSetReader reader) throws Exception {
    final Connection conn = getConnection();
    try {
        final Statement stmnt = conn.createStatement();
        try {
            final ResultSet rs = stmnt.executeQuery(query);
            try {
                while (rs.next()) {
                    reader.read(rs);
                }
            } finally {
                rs.close();
            }
        } finally {
            stmnt.close();
        }
    } finally {
        conn.close();
    }
}

与调用网站上的匿名类一起使用,如下所示

    withResultSet("select * from pg_user", new ResultSetReader() {
        @Override
        public void read(ResultSet rs) throws SQLException {
            System.out.println(rs.getObject(1));
        }
    });

这样在使用网站上没有try / catch,没有人忘记关闭资源(并且没有人错误地关闭资源)。

如果Java 8可用,ResultSetReader接口可以替换为闭包。