简体   繁体   中英

Java implicit try-with-resources

I am wondering if the following code uses the try-with-resources correctly.

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

The arguments are not important, the only important thing is:

  • new QueryBuilder().build(); returns a PreparedStatement .

I completely understand that rs will be closed, but will the PreparedStatement also be closed, and if so, for what reason? Because the ResultSet closes or because of the try-with-resources?

PreparedStatement#close() will automatically close any associated result sets but the reverse is not true because statements are reusable after their result sets are closed.

Look at the javadoc of ResultSet#close() :

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed

And then Statement#close() :

Note: When a Statement object is closed, its current ResultSet object, if one exists, is also closed.

This usage looks very crappy to me :

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

If executed enough times it will leak all of the available cursors, because cursors are associated with the Statement not with ResultSet .

Hence to close the underlying PreparedStatement with try-with-resources statement , just declare it within the try statement :

A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically .

Look at this answer from assylias , declare the PreparedStatement as well as ResultSet inside the try statement.

Since you are not looking for a memory leak, but a resource leak . The memory of the PreparedStatement will be collected eventually and it's memory freed, as it is not referenced anymore after execution of your method given the way it is initialized , however, the resources hold by the Statement is not closed .

You can include several resources in the try, and they will all be closed - which is necessary if you want the PreparedStatement to be closed:

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

According to the documentation here - tryResourceClose , as I read it, it is specific to resources that are declared .

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

Reading further down you see:

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)
  ) {

I suggest the correct answer to you issue is the following:

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

As you correctly stated, rs will be closed. This means actually that the close() method will be invoked on rs . So the try-with-ressource statement doesn't explictly close the PreparedStatement in your case.

If it's closed otherwise (in context of the rs.close() ) is kind of hard to say without knowing the implementation ;-)

EDIT

As @TheNewIdiot correctly found out, your PreparedStatement won't be closed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM