Подтвердить что ты не робот

Повторное использование ресурсов Statement и Resultset из предыдущего использования? Или я должен явно закрыть их перед повторным использованием?

Пример кода:

        aStmt = aConn.prepareStatement(aQuery);
        aRset = aStmt.executeQuery(cQuery);

        while (cRset.next()) {
            //stuff to determine value of parm1

            aStmt.setString(1, parm1);                
            aRset = aStmt.executeQuery(); 

            //more stuff
        }

Должен ли я закрывать aStmt и aRset после каждого цикла внутри оператора while? Или повторное использование их в последующих циклах освобождает память/ресурсы, используемые из предыдущих циклов?

4b9b3361

Ответ 1

Поведение результатов и (подготовленных) операторов явно описано в Java API. Я предлагаю вам прочитать фактическую документацию (и спецификацию JDBC), чтобы получить подробную информацию.

API Statement говорит:

По умолчанию только один объект ResultSet для объекта Statement может быть открыт одновременно. Поэтому, если чтение одного объекта ResultSet чередуется с чтением другого, каждый из них должен быть сгенерирован разными объектами Statement. Все методы выполнения в интерфейсе Statement неявно закрывают текущий объект ResultSet статусом, если существует открытый.

(основное внимание).

В вашем конкретном коде, когда вы вызываете aStmt.executeQuery(), старый ResultSet, назначенный aRset, неявно закрывается драйвером. Тем не менее, было бы лучше явно закрыть его самостоятельно (или использовать Java 7 try-with-resources), чтобы вы не забыли закрыть ResultSet в последней итерации через цикл.

Теперь перед PreparedStatement: при подготовке инструкции (в общем случае реализация может меняться), запрос отправляется на сервер для компиляции. При выполнении параметры для этого конкретного выполнения отправляются на сервер. Вызов close() на aStmt приведет к тому, что подготовленный оператор будет освобожден на сервере, что явно НЕ, что вы хотите здесь, так как вы хотите повторно использовать оператор с разными значениями для его параметра.

Итак, коротко

  • Закрытие ResultSet здесь не является технически необходимым (за исключением последнего ResultSet), но лучше сделать это явно
  • Вы должны закрыть только PreparedStatement, когда закончите с ним.

Использование try-with-resources - один из способов устранить часть путаницы по этим проблемам, так как ваш код будет автоматически выпускать ресурсы, когда это будет сделано с ним ( по окончании использования):

try (
    ResultSet cRset = cStmt.executeQuery(cQuery);
    PreparedStatement aStmt = aConn.prepareStatement(aQuery);
) {
    while (cRset.next()) {
        //stuff to determine value of parm1

        aStmt.setString(1, parm1);                
        try (ResultSet aRset = aStmt.executeQuery()) {
            //more stuff
        }
    }
}

В конце этого фрагмента кода все ресурсы JDBC правильно закрыты (в правильном порядке, даже если произошли исключения и т.д.)

Ответ 2

Нет, вы не можете закрыть ResultSet и Statement внутри цикла while.

Вам нужно закрыть их после цикла.

Также, если вы хотите повторно использовать PreparedStatement, вы можете закрыть его, пока не будете готовы к обработке.

Лучшее правило - закрыть такие ресурсы в том же блоке, который был создан. В вашем случае лучше всего закрыть ресурсы в блоке finally после ловли SQLException.

например.

try {
    aStmt = aConn.prepareStatement(aQuery);
    cRset = cStmt.executeQuery(cQuery);

    while (cRset.next()) {
        //stuff to determine value of parm1

        aStmt.setString(1, parm1);
        try {
            aRset = aStmt.executeQuery();
        } finally {
            aRset.close();
        }

        //more stuff
    }
} catch (SQLException ex) {
    // Do error handling
} finally {
    // Close Resultset
}

В Java 7 вы можете использовать try с ресурсами.

Ответ 3

PreparedStatement API: оператор SQL предварительно скомпилирован и хранится в объекте PreparedStatement. Затем этот объект можно использовать для эффективного выполнения этого утверждения несколько раз.

Но вы не можете повторно использовать объект ResultSet. Когда вы вызываете executeQuery на объект PreparedStatement во второй раз, когда создается новый ResultSet, если вы не закрываете предыдущий ResultSet, вы рискуете получить утечку ресурса.