如果我有以下代码,这是关闭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
}
答案 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 - 嵌套与否)会使代码混乱。摆脱一种方法是集中管理资源,并使用监听器/读取器。
因此,在库中,您可以定义Reader
和with...
方法:
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
接口可以替换为闭包。