java – 尝试/尝试使用资源以及Connection,Statement和ResultSet关闭
作者:互联网
我最近和我的教授讨论了如何处理基本的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(即使Statement语句明确说明它将关闭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,但是她告诉我她很好,只要在文档中很清楚所有关闭.您是否可以通过类似示例提供官方文档的任何链接,或者根据文档显示此代码没有问题?
解决方法:
TL;博士
>理论上,关闭语句会关闭结果集.
>在实践中,一些错误的JDBC驱动程序实现未能如此做到这一点,这是出了名的.因此,教练的建议是她从硬敲门学校那里学到的.除非您熟悉可能为应用程序部署的每个JDBC驱动程序的每个实现,否则请使用try-with-resources自动关闭JDBC工作的每个级别,例如语句和结果集.
使用try-with-resources语法
您的所有代码都没有完全使用try-with-resources.在try-with-resources语法中,您可以在大括号之前在括号中声明并实例化Connection,PreparedStatement和ResultSet.
虽然您的ResultSet未在上一个代码示例中显式关闭,但应在其语句关闭时间接关闭它.但是如下所述,由于JDBC驱动程序错误,它可能无法关闭.
AutoCloseable
实现AutoCloseable
的任何此类对象将自动调用其close方法.所以不需要那些最终的条款.
对于阅读本文的人文专业,是的,Java团队拼错了“可关闭”.
你怎么知道哪些对象是可以自动关闭的,哪些不是?查看他们的类文档,看看它是否将AutoCloseable声明为超级接口.相反,请参阅the JavaDoc page for AutoCloseable
以获取所有捆绑子接口和实现类的列表(实际上是几十个).例如,对于SQL工作,我们看到Connection,Statement,PreparedStatement,ResultSet和RowSet都可以自动关闭,但DataSource
不是.
请参见Oracle教程,The try-with-resources Statement.
代码示例
您的上一个代码示例接近良好,但应该在try-with-resources语句中包装ResultSet以自动关闭.
引用ResultSet
JavaDoc:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
正如您的老师一直建议的那样,某些JDBC驱动程序存在严重缺陷,这些缺陷未能达到JDBC规范在Statement或PreparedStatement关闭时关闭ResultSet的承诺.许多程序员习惯于显式关闭每个ResultSet对象.
现在使用try-with-resources语法可以更轻松地完成这项额外任务.在实际工作中,您可能会尝试使用所有AutoCloseable对象(例如ResultSet).所以我自己的观点是:为什么不把它作为资源尝试呢?没有伤害,使您的代码更自我记录您的意图,如果您的代码遇到其中一个错误的JDBC驱动程序,它可能会有所帮助.唯一的成本是一对parens,假设你有一个尝试捕获 – 否则就位.
如Oracle Tutorial所述,一起声明的多个AutoCloseable对象将以相反的顺序关闭.
提示:try-with-resources语法允许在最后声明的资源项上使用可选分号.我将分号作为习惯包括在内,因为它能很好地读取,并且是一致的,并且有助于剪切和粘贴编辑.我将它包含在您的PreparedStatement s2行中.
public void doQueries() throws MyException{
// First try-with-resources.
try ( Connection con = DriverManager.getConnection( dataSource ) ;
PreparedStatement s1 = con.prepareStatement( updateSqlQuery ) ;
PreparedStatement s2 = con.prepareStatement( selectSqlQuery ) ;
) {
… Set parameters of PreparedStatements, etc.
s1.executeUpdate() ;
// Second try-with-resources, nested within first.
try (
ResultSet rs = s2.executeQuery() ;
) {
… process ResultSet
} catch ( SQLException e2 ) {
… handle exception related to ResultSet.
}
} catch ( SQLException e ) {
… handle exception related to Connection or PreparedStatements.
}
}
我想这种工作有一种更优雅的语法,可能是在未来的编程语言中发明的.但是现在,我们已经尝试了资源,我确实很愉快地使用它.虽然try-with-resources并不是非常优雅,但它比旧语法有了很大的改进.
顺便说一下,Oracle建议使用DataSource实现来获取连接,而不是代码中看到的DriverManager方法.在整个代码中使用DataSource可以更轻松地切换驱动程序或切换到连接池.查看JDBC驱动程序是否提供DataSource的实现.
更新:Java 9
现在,在Java 9中,您可以在try-with-resources之前初始化资源.见this article.
标签:correctness,java,try-with-resources 来源: https://codeday.me/bug/20191001/1840554.html