在写JDBC代码时,一般都会用如下的“八股文”的形式:
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement("select * from booktab");
rs = pstmt.executeQuery();
while (rs.next()) {
// traverse the records
}
} catch (SQLException e) {
// handle exception
} finally {
if (rs != null) { try { rs.close(); } catch (Exception e) { } }
if (pstmt != null) { try { pstmt.close(); } catch (Exception e) { } }
if (conn != null) { try { conn.close(); } catch (Exception e) { } }
}
两个注意点:1、将关闭连接代码写到finally块中,即不管是否抛异常都要执行;2、要进行非空判断(如pstmt != null),防止抛NullPointerException异常。
作者学JDBC的时候,也是照着上述范例代码,稍作修改用到自己的程序中,前阵子突发奇想,在关闭中能否只调用Connection.close()方法而不事先调用ResultSet和Statement的close()方法?通过实验(MySQL5.1.14+mysql-connector-java-5.0.5-bin.jar的驱动程序),验证了是可行的。
首先,去掉ResultSet和Statement的close()方法调用,在finally块中只调用Connection.close():
if (conn != null) { try { conn.close(); } catch (Exception e) { } }
再在eclipse中进行单步跟踪,在上面代码上加一个断点,执行前查看rs和pstmt对象的属性isClosed值为false,执行完conn.close()方法后,rs和pstmt对象的属性isClosed值已经被修改为true,表明已经被关闭。
根据上面的分析,笔者虽然没有去读mysql的jdbc源代码,但猜测在Connection对象中会保存一个Statement对象的列表,并且每个Statement对象也会保存一个ResultSet对象,从而在调用Connection.close()方法时,会递归调用ResultSet.close()和Statement.close()方法,最后再关闭connection。
不知道其它数据库(如SQLServer/DB2/Sybase/PostgreSQL等)的jdbc驱动是否也是这样处理的,猜想应该是一样的。虽然可以省略两行程序,但从代码的可读性以及编程习惯上来说,加上会更好一些,省略了的话,代码的连贯性不好,因而是不推荐的。