Java ResultSet未正确关闭

时间:2019-03-25 21:42:29

标签: java plsql try-catch resultset database-cursor

我有一个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");
}

我开始遇到“超出最大游标数”错误。我检查了我的方法以确定ResultSet是否未关闭。 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子句中再次调用了它们,它们成功了。这怎么可能?

2 个答案:

答案 0 :(得分:1)

使用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");
}

答案 1 :(得分:0)

否,不需要打两次电话

否,JDBC不需要两次调用close。我怀疑还有其他事情发生。

我们不能确定地确定您的代码中发生了什么。我们不知道您所谓的第二通电话是否确实解决了该问题。例如,Statement::close的文档说:

  

在已关闭的Statement对象上调用close方法无效。

尝试资源

正如Answer by Andreas所建议的那样,您应该使用try-with-resources。

请参阅:

将try-with-resources用于JDBC以及实现AutoCloseable的任何资源。

您可以在您的try( … ) 中放入一个或多个资源。用分号分隔,最后一个分号是可选的。 Java将跟踪资源,每个资源以打开的相反顺序关闭。如果中间发生异常,则Java不会尝试关闭空资源对象。这样可以大大简化您的编码。