【发布时间】:2014-05-05 11:41:03
【问题描述】:
我最近和我的教授讨论了如何处理基本的 jdbc 连接方案。假设我们要执行两个查询,这就是他的建议
public void doQueries() throws MyException{
Connection con = null;
try {
con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
rs.close();
s2.close();
s1.close();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't really do anything
}
}
}
我不喜欢这种方法,对此我有两个问题:
1.A) 我认为,如果在我们做“其他事情”的地方或在rs.close() 或s2.close() 行中抛出任何异常,那么当方法结束时s1 不会被关闭。我说的对吗?
1.B) 教授一直要求我明确关闭 ResultSet(即使声明文档明确表示它将关闭 ResultSet)她说 Sun 推荐它。有什么理由这样做吗?
现在我认为这是同一件事的正确代码:
public void doQueries() throws MyException{
Connection con = null;
PreparedStatement s1 = null;
PreparedStatement s2 = null;
try {
con = DriverManager.getConnection(dataSource);
s1 = con.prepareStatement(updateSqlQuery);
s2 = con.prepareStatement(selectSqlQuery);
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
} finally {
try {
if (s2 != null) {
s2.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (s1 != null) {
s1.close();
}
} catch (SQLException e3) {
// Can't do nothing
}
try {
if (con != null) {
con.close();
}
} catch (SQLException e2) {
// Can't do nothing
}
}
}
2.A) 这段代码正确吗? (是否保证方法结束时全部关闭?)
2.B) 这非常大而且冗长(如果有更多的语句,情况会变得更糟)有没有更短或更优雅的方法来做到这一点而不使用 try-with-resources?
最后这是我最喜欢的代码
public void doQueries() throws MyException{
try (Connection con = DriverManager.getConnection(dataSource);
PreparedStatement s1 = con.prepareStatement(updateSqlQuery);
PreparedStatement s2 = con.prepareStatement(selectSqlQuery))
{
// Set the parameters of the PreparedStatements and maybe do other things
s1.executeUpdate();
ResultSet rs = s2.executeQuery();
} catch (SQLException e) {
throw new MyException(e);
}
}
3) 这段代码正确吗?我认为我的教授不喜欢这种方式,因为没有明确关闭 ResultSet,但她告诉我,只要在文档中清楚地表明所有内容都已关闭,她就可以接受。能否给出官方文档的链接,有类似的例子,或者根据文档显示这段代码没有问题?
【问题讨论】:
-
A ResultSet object is automatically closed when the Statement object that generated it is closed阅读here -
2.A) 这段代码正确吗? 不,
close可能会抛出RuntimeException。在 try-with-resources 之前,我使用了嵌套的 try/finally 块,因此每个资源都有自己的 finally。 -
我认为你的教授说自己关闭 ResultSet 是对的。依赖其他代码来做是危险的。你怎么知道在未来的版本中他们不会改变它,所以 ResultSets 不会自动关闭?另外,我会捕获 Throwable 而不是 SqlException。它将涵盖所有可能的场景。
-
@Trollkemada
RuntimeException可以总是被抛出。您不希望有错误的驱动程序抛出NullPointerException来阻止资源被释放。 -
已知一些 JDBC 驱动程序在关闭连接时无法正确关闭 ResultSet 的问题。因此,虽然理论上您对文档的解释是正确的,说您不需要明确关闭 ResultSet,但实际上您应该这样做。
标签: java correctness try-with-resources