Java ResultSet не закрывается должным образом - PullRequest
0 голосов
/ 26 марта 2019

У меня есть 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");
}

Я столкнулся с ошибкой "превышено максимальное количество курсоров". Я проверил свои методы, чтобы определить, не закрываются ли ResultSets. Предложение catch никогда не срабатывало, и «test1» печатался каждый раз. Это означает, что строки rs.close () и stmt.close () НЕ пропускаются. И все же ResultSets на самом деле не закрываются.

Я добавил предложение 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 ]

1 голос
/ 26 марта 2019

Использовать 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");
}
0 голосов
/ 26 марта 2019

Нет, не нужно звонить дважды

Нет, JDBC не нужно дважды вызывать close. Я подозреваю, что происходит что-то еще.

Мы не можем с уверенностью сказать, что происходит в вашем коде. Мы не можем знать, действительно ли ваш второй звонок решил проблему. Например, документация для Statement::close гласит:

Вызов метода close для объекта Statement, который уже закрыт, не имеет никакого эффекта.

примерочный с-ресурсами

Как подсказывает Answer by Andreas , вы должны использовать попытку с ресурсами.

См:

Используйте try-with-resources для JDBC, а также для любого ресурса, реализующего AutoCloseable.

Вы можете поместить один или несколько ресурсов в ваш try( … ). Разделяйте точками с запятой, последняя точка с запятой необязательна. Java будет отслеживать ресурсы, каждый из которых будет закрыт в обратном порядке открытия. Если в середине происходит исключение, Java знает, что нельзя пытаться закрыть нулевые объекты ресурса. Это значительно упрощает кодирование.

...