Неявная попытка использования ресурсов в Java

Мне интересно, правильно ли следующий код использует попытку с ресурсами.

try (ResultSet rs = new QueryBuilder(connection, tableName(), getPaths(), searchQuery()).add(constraint).build().executeQuery()) {
    while (rs.next()) {
        beans.add(createBean(rs));
    }
}

Аргументы не важны, главное:

  • new QueryBuilder().build(); возвращает PreparedStatement.

Я прекрасно понимаю, что rs будет закрыто, но PreparedStatement тоже будет закрыто, и если да, то по какой причине? Потому что ResultSet закрывается или из-за попытки с ресурсами?


person skiwi    schedule 22.07.2013    source источник


Ответы (4)


PreparedStatement#close() автоматически закроет все связанные наборы результатов, но обратное неверно, поскольку операторы можно использовать повторно после закрытия их наборов результатов.

Посмотрите javadoc ResultSet#close ():

Примечание. Объект ResultSet автоматически закрывается сгенерировавшим его объектом Statement при закрытии этого объекта Statement.

А затем Statement#close()< /а>:

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

Это использование выглядит очень дрянным для меня:

ResultSet rs=conn.createStatement().executeQuery();

Если выполнить его достаточное количество раз, он приведет к утечке всех доступных курсоров, потому что курсоры связаны с Statement, а не с ResultSet.

Следовательно, чтобы закрыть базовый PreparedStatement с помощью оператор try-with-resources, просто объявите его в операторе try:

Оператор try-with-resources параметризуется переменными (известными как ресурсы), которые инициализируются перед выполнением блока try и закрываются автоматически.

Посмотрите на этот ответ от assylias, объявите PreparedStatement, а также ResultSet внутри оператора try.

Поскольку вы ищете не утечку памяти, а утечку ресурсов. В конечном итоге память PreparedStatement будет собрана, и ее память будет освобождена, поскольку на нее больше не ссылаются после выполнения вашего метода, учитывая способ его инициализации, однако ресурсы, удерживаемые Statement, не закрываются.

person AllTooSir    schedule 22.07.2013

Вы можете включить в попытку несколько ресурсов, и все они будут закрыты — что необходимо, если вы хотите, чтобы PreparedStatement был закрыт:

try (PreparedStatement ps = new QueryBuilder(connection, tableName(), getPaths(), searchQuery()).add(constraint).build();
        ResultSet rs = ps.executeQuery();) {
    while (rs.next()) {
        beans.add(createBean(rs));
    }
}
person assylias    schedule 22.07.2013
comment
У меня было это (и теперь будет снова), но я как бы пытался избежать двух разных заявлений. - person skiwi; 22.07.2013
comment
@skiwi Я на самом деле нахожу разделение на два утверждения более читабельным, а не менее. - person assylias; 22.07.2013
comment
Вам действительно нужно объявлять ResultSet в попытке с ресурсами? Нельзя ли безопасно объявить его в теле блока try и автоматически закрыть с помощью PreparedStatement, когда он будет закрыт? Не пытаясь придираться к вашему коду, я просто не уверен, так это будет работать или нет. - person Greg H; 04.02.2014
comment
@GregH Я никогда не уверен на 100%, что происходит с ResultSet, когда оператор закрывается, и я думаю, что читал, что некоторые драйверы не освобождают ресурсы, как вы ожидаете. Также ничего не стоит закрыть ResultSet, поэтому я просто делаю это. Но вы правы в том, что должно быть безопасно поместить ResultSet rs = ps.executeQuery() в тело блока try, потому что он должен закрываться, когда вы закрываете PreparedStatement. - person assylias; 04.02.2014

Согласно документации здесь - tryResourceClose, как я ее читал, это относится к ресурсам, которые являются declared.

The try-with-resources statement is a try statement that declares one or more resources.

Читая дальше, вы видите:

You may declare one or more resources in a try-with-resources statement. The following example retrieves the names of the files packaged in the zip file zipFileName and creates a text file that contains the names of these files:

 try (
      java.util.zip.ZipFile zf =
         new java.util.zip.ZipFile(zipFileName);
    java.io.BufferedWriter writer = 
        java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
  ) {

Я предлагаю правильный ответ на ваш вопрос:

try{
  PreparedStatement statement = new QueryBuilder(connection, tableName(), getPaths(), searchQuery())
       .add(constraint).build();
  ResultSet rs = statement.executeQuery()) 
}
person John B    schedule 22.07.2013

Как вы правильно заметили, rs будет закрыто. Фактически это означает, что метод close() будет вызываться для rs. Таким образом, оператор try-with-resource явно не закрывает PreparedStatement в вашем случае.

Если он закрыт иначе (в контексте rs.close()), трудно сказать, не зная реализации ;-)

ИЗМЕНИТЬ

Как правильно выяснил @TheNewIdiot, ваш PreparedStatement не будет закрыт.

person André Stannek    schedule 22.07.2013