当前位置:  开发笔记 > 编程语言 > 正文

在哪里关闭java PreparedStatements和ResultSet?

如何解决《在哪里关闭javaPreparedStatements和ResultSet?》经验,为你挑选了6个好方法。

考虑一下代码:

PreparedStatement ps = null;
ResultSet rs = null;
try {
  ps = conn.createStatement(myQueryString);
  rs = ps.executeQuery();
  // process the results...
} catch (java.sql.SQLException e) {
  log.error("an error!", e);
  throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
  ps.close();
  rs.close();
}

上面没有编译,因为都PreparedStatement.close()ResultSet.close()抛出java.sql.SQLException.那么我要在finally子句中添加一个try/catch块吗?或者将close语句移动到try子句中?或者只是不打扰打电话?



1> erickson..:

在Java 7中,不应显式关闭它们,而应使用自动资源管理来确保关闭资源并正确处理异常.异常处理的工作方式如下:

Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
      No         |        No          | Continue normally
      No         |        Yes         | Throw the close() exception
      Yes        |        No          | Throw the exception from try block
      Yes        |        Yes         | Add close() exception to main exception
                 |                    |  as "suppressed", throw main exception

希望这是有道理的.允许漂亮的代码,像这样:

private void doEverythingInOneSillyMethod(String key)
  throws MyAppException
{
  try (Connection db = ds.getConnection()) {
    db.setReadOnly(true);
    ...
    try (PreparedStatement ps = db.prepareStatement(...)) {
      ps.setString(1, key);
      ...
      try (ResultSet rs = ps.executeQuery()) {
        ...
      }
    }
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

在Java 7之前,最好使用嵌套的finally块,而不是测试null的引用.

我将展示的示例可能看起来很难看深嵌套,但实际上,设计良好的代码可能不会在同一个方法中创建连接,语句和结果; 通常,每个嵌套级别都涉及将资源传递给另一个方法,该方法将其用作另一个资源的工厂.使用这种方法,来自a close()的异常将掩盖try块内的异常.这可以克服,但它会导致代码更加混乱,并且需要一个自定义异常类,它提供Java 7中存在的"抑制"异常链.

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}


Ctrl-Shift-F到您心中的内容!;)
如果你把终点放在与右大括号相同的线上,那就不那么难看了.;)
@ceving没有人建议可以避免结束陈述.你在回应什么?

2> Steve B...:

如果你真的在手动推出自己的jdbc,它肯定会变得混乱.最后的close()需要用自己的try catch包装,这至少是丑陋的.您无法跳过关闭,但是当连接关闭时,资源将被清除(如果您正在使用池,则可能不会立即清除).实际上,使用框架(例如hibernate)来管理数据库访问的一个主要卖点是管理连接和结果集处理,这样你就不会忘记关闭.

你可以做一些像这样简单的事情,至少可以隐藏这些混乱,并保证你不会忘记一些事情.

public static void close(ResultSet rs, Statement ps, Connection conn)
{
    if (rs!=null)
    {
        try
        {
            rs.close();

        }
        catch(SQLException e)
        {
            logger.error("The result set cannot be closed.", e);
        }
    }
    if (ps != null)
    {
        try
        {
            ps.close();
        } catch (SQLException e)
        {
            logger.error("The statement cannot be closed.", e);
        }
    }
    if (conn != null)
    {
        try
        {
            conn.close();
        } catch (SQLException e)
        {
            logger.error("The data source connection cannot be closed.", e);
        }
    }

}

然后,

finally {
    close(rs, ps, null); 
}


请注意,根据JavaDoc for Statement,ResultSet将作为关闭语句的副作用而关闭,因此在此示例中并非严格必要(但不会受到影响).http://java.sun.com/javase/6/docs/api/java/sql/Statement.html#close()

3> Michael Myer..:

对于文件I/O,我通常会在finally块中添加try/catch.但是,您必须小心不要从finally块中抛出任何异常,因为它们将导致原始异常(如果有)丢失.

有关数据库连接关闭的更具体示例,请参阅此文章.



4> BraveSirFoob..:

不要浪费时间编写低级异常管理,使用更高级别的API(如Spring-JDBC)或围绕连接/语句/ rs对象的自定义包装器来隐藏凌乱的try-catch循环代码.



5> 小智..:

另请注意:

"当一个Statement对象关闭时,它的当前ResultSet对象(如果存在)也会关闭."

http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close()

仅在最终关闭PreparedStatement并且仅在它尚未关闭时才足够.如果你想要非常特别,请关闭ResultSet FIRST,而不是在关闭PreparedStatement之后(关闭它之后,像这里的一些示例一样,实际上应该保证异常,因为它已经关闭).


根据您引用的文档,在已经关闭的Statement上调用Statement.close()无效.多次关闭一个Statement不会抛出异常,因此对于ResultSet执行相同操作应该同样无害.ResultSet中的文件并没有明确说这一点,但它也不会说,你不应该关闭它不止一次......这迂腐咆哮的全部意义在于,它并不能保证一个例外.虽然最好先关闭ResultSet,以防某些实现以这种方式运行.
我无法自拔.我必须指出这是一个非常有用的答案,而上面说的"使用框架"只会让我感到畏缩.

6> Jon Skeet..:

我通常有一个实用方法可以关闭这样的事情,包括注意不要尝试使用空引用做任何事情.

通常如果close()抛出异常我实际上并不关心,所以我只记录异常并吞下它 - 但另一种选择是将其转换为RuntimeException.无论哪种方式,我建议在一个易于调用的实用方法中进行,因为您可能需要在很多地方执行此操作.

请注意,如果关闭PreparedStatement失败,您当前的解决方案将不会关闭ResultSet - 最好使用嵌套的finally块.

推荐阅读
mylvfamily
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有