问题
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 aPreparedStatement
.
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?
回答1:
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 .
回答2:
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));
}
}
回答3:
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())
}
回答4:
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.
来源:https://stackoverflow.com/questions/17788132/java-implicit-try-with-resources