【问题标题】:Java implicit try-with-resourcesJava 隐式 try-with-resources
【发布时间】:2013-07-21 05:18:01
【问题描述】:

我想知道以下代码是否正确使用了 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(); 返回 PreparedStatement

我完全理解rs 将被关闭,但PreparedStatement 也会被关闭,如果是,是什么原因?因为ResultSet 关闭还是因为try-with-resources?

【问题讨论】:

    标签: java try-with-resources


    【解决方案1】:

    PreparedStatement#close() 将自动关闭所有关联的结果集,但反之则不然,因为语句在其结果集关闭后是可重用的。

    ResultSet#close()的javadoc:

    注意:当 Statement 对象关闭时,生成它的 Statement 对象会自动关闭 ResultSet 对象

    然后Statement#close():

    注意:当一个Statement对象被关闭时,它当前的ResultSet对象,如果存在的话,也被关闭。

    这种用法对我来说看起来很糟糕:

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

    如果执行的次数足够多,它将泄漏所有可用的游标,因为游标与Statement 相关联,而不是与ResultSet 相关联。

    因此用try-with-resources statement 关闭底层PreparedStatement,只需在try 语句中声明它:

    try-with-resources 语句使用变量(称为资源)进行参数化,这些变量在执行 try 块之前被初始化并自动关闭

    查看this answer from assylias,在try 语句中声明PreparedStatementResultSet

    因为您不是在寻找 内存泄漏,而是在寻找资源泄漏PreparedStatement 的内存最终将被收集并释放它的内存,因为在执行您的方法后不再引用它,因为它是初始化的,但是,Statement 持有的资源没有关闭。

    【讨论】:

      【解决方案2】:

      如您所说,rs 将被关闭。这实际上意味着close() 方法将在rs 上被调用。因此,在您的情况下,try-with-ressource 语句不会明确关闭 PreparedStatement

      如果它以其他方式关闭(在 rs.close() 的上下文中)在不知道实现的情况下很难说 ;-)

      编辑

      正如@TheNewIdiot 正确发现的那样,您的PreparedStatement 不会被关闭。

      【讨论】:

        【解决方案3】:

        您可以在 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));
            }
        }
        

        【讨论】:

        • 我曾经有过(现在还会有),但我试图避免两种不同的声明。
        • @skiwi 我实际上发现将它分成两个更易读的语句,而不是更少。
        • 你真的需要在try-with-resources中声明ResultSet吗?难道不能在try块的主体中​​安全地声明,关闭时由PreparedStatement自动关闭吗?不想挑剔你的代码,我只是不确定它是否会这样工作。
        • @GregH 我永远不能 100% 确定当 Statement 关闭时 ResultSet 会发生什么,我想我已经读过一些驱动程序不会像您期望的那样释放资源。关闭 ResultSet 也不需要任何费用,所以我就这样做了。但是你是对的,将ResultSet rs = ps.executeQuery() 放在 try 块的主体中​​应该是安全的,因为它应该在你关闭 PreparedStatement 时关闭。
        【解决方案4】:

        根据文档here - 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()) 
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多