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

Мне интересно, правильно ли использует следующий код try-with-resources.

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

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

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

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

Ответы

Ответ 1

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

Посмотрите на javadoc ResultSet # закрыть():

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

И затем Statement # close():

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

В соответствии с документацией здесь - 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()) 
}

Ответ 4

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

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

ИЗМЕНИТЬ

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