简体   繁体   English

Java隐式尝试资源

[英]Java implicit try-with-resources

I am wondering if the following code uses the try-with-resources correctly. 我想知道以下代码是否正确使用try-with-resources。

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 . 返回PreparedStatement

I completely understand that rs will be closed, but will the PreparedStatement also be closed, and if so, for what reason? 我完全理解rs会被关闭,但是PreparedStatement也会被关闭,如果是这样,出于什么原因? Because the ResultSet closes or because of the try-with-resources? 因为ResultSet关闭还是因为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. PreparedStatement #close()将自动关闭任何关联的结果集,但反之则不正确,因为语句在结果集关闭后可重复使用。

Look at the javadoc of ResultSet#close() : 查看ResultSet#close()的javadoc:

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed 注意:当Statement对象关闭时,Statement对象会自动关闭,该对象会生成它

And then Statement#close() : 然后是Statement#close()

Note: When a Statement object is closed, its current ResultSet object, if one exists, is also closed. 注意:关闭Statement对象时,其当前ResultSet对象(如果存在)也将关闭。

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 . 如果执行足够多次,它将泄漏所有可用游标,因为游标与Statement不与ResultSet相关联。

Hence to close the underlying PreparedStatement with try-with-resources statement , just declare it within the try statement : 因此,要使用try-with-resources语句关闭底层PreparedStatement ,只需在try语句中声明它:

A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically . try-with-resources语句使用变量(称为资源)进行参数化,这些变量在执行try块之前初始化并自动关闭

Look at this answer from assylias , declare the PreparedStatement as well as ResultSet inside the try statement. 从assylias这个答案 ,在try语句中声明PreparedStatementResultSet

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 . PreparedStatement的内存最终将被收集并释放内存,因为在执行初始化方法后,它不再被引用,但是, Statement所持有的资源没有被关闭。

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 ,这是必需的:

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 . 根据这里的文档- tryResourceClose ,正如我所读到的,它特定于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. 正如您所说, rs将被关闭。 This means actually that the close() method will be invoked on rs . 这实际上意味着将在rs上调用close()方法。 So the try-with-ressource statement doesn't explictly close the PreparedStatement in your case. 因此,try-with-ressource语句在您的情况下不会明确地关闭PreparedStatement

If it's closed otherwise (in context of the rs.close() ) is kind of hard to say without knowing the implementation ;-) 如果它被关闭,否则(在rs.close()上下文中)在不知道实现的情况下很难说;-)

EDIT 编辑

As @TheNewIdiot correctly found out, your PreparedStatement won't be closed. 正如@TheNewIdiot正确找到的那样,您的PreparedStatement将不会被关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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