我有一个Java应用程序,其中包含许多代码片段,如下所示。 非常简单的 Oracle 数据库查询。 返回并解析有效数据,然后调用 close() 函数。
ResultSet rs = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM example");
while (rs.next())
{
// do stuff
}
rs.close();
stmt.close();
System.out.println("test1");
}
catch (Exception e)
{
System.out.println("error1");
}
我开始遇到"超出最大游标数"错误。 我检查了我的方法以确定结果集是否未关闭。catch
子句从未被触发,并且每次都打印"test1"。 这意味着 rs.close() 和 stmt.close() 行不会被跳过。 然而,结果集实际上并没有被关闭。
我添加了一个finally
条款,它解决了这个问题。
finally
{
if (rs != null)
{
try
{
rs.close();
System.out.println("test2");
}
catch (Exception e)
{
System.out.println("error2");
}
}
if (stmt != null)
{
try
{
stmt.close();
System.out.println("test3");
}
catch (Exception e)
{
System.out.println("error3");
}
}
}
输出:
test1
test2
test3
我的问题是,为什么rs.close()和stmt.close()需要调用两次?try
子句中的调用似乎没有任何作用。 然而,我在finally
条款中再次称呼他们,他们成功了。 这怎么可能?
Use try-with-resources (Java 7+):
try (Statement stmt = conn.createStatement()) {
try (ResultSet rs = stmt.executeQuery("SELECT * FROM example")) {
while (rs.next()) {
// do stuff
}
System.out.println("test1");
}
} catch (Exception e) {
System.out.println("error1");
}
不,无需调用两次
不,在 JDBC 中没有必要调用close
两次。我怀疑还有其他事情发生。
我们无法确定您的代码中发生了什么。我们无法知道您所谓的第二个电话是否真的解决了问题。例如,Statement::close
的文档说:
对已关闭的语句对象调用方法 close 不起作用。
试用资源
正如Andreas的答案所建议的那样,您应该使用资源尝试。
看:
- Java 7 关于试用资源的技术说明。
- 甲骨文教程。
- Java 9 增强了对资源的尝试,使用以前在 Try-with-Resource 语句中创建的变量。
对 JDBC 以及任何实现资源的资源AutoCloseable
使用试用资源。
您可以将一个或多个资源放入try( … )
中。用分号分隔,最后一个分号是可选的。Java将跟踪资源,每个资源都以与打开相反的顺序关闭。如果中间发生异常,Java 知道不要尝试关闭空资源对象。这大大简化了您的编码。