17

Connection.close()可能会抛出SqlException,但我一直认为忽略任何此类异常是安全的(而且我从未见过不忽略它们的代码)。

通常我会写:

 try{
    connection.close();
 }catch(Exception e) {}

或者

 try{
    connection.close();
 }catch(Exception e) {
     logger.log(e.getMessage(), e); 
 }

问题是:

  1. 这是不好的做法(并且在忽略此类异常时是否有人遇到问题)。
  2. 什么Connection.close()时候抛出任何异常。
  3. 如果不好,我应该如何处理异常。

评论:

我知道丢弃异常是邪恶的,但我只提到关闭连接时抛出的异常(正如我所见,这在这种情况下相当普遍)。

有谁知道什么时候Connection.close()可以扔东西?

4

12 回答 12

16

实际上,您所做的是(几乎)最佳实践 :-) 这是我在 Spring 的 JdbcUtils.java 中看到的。因此,您可能想要添加另一个 Catch 块。

/**
 * Close the given  ResultSet and ignore any thrown exception.
 * This is useful for typical finally blocks in manual  code.
 * @param resultSet the  ResultSet to close
 * @see javax.resource.cci.ResultSet#close()
 */
private void closeResultSet(ResultSet resultSet) {
  if (resultSet != null) {
    try {
      resultSet.close();
    }
    catch (SQLException ex) {
      logger.debug("Could not close  ResultSet", ex);
    }
    catch (Throwable ex) {
      // We don't trust the  driver: It might throw RuntimeException or Error.
      logger.debug("Unexpected exception on closing  ResultSet", ex);
    }
  }
}
于 2008-10-30T02:52:32.660 回答
12

总的来说,我有很多天被人们扔掉这样的异常所浪费。

我建议遵循一些基本规则,但有例外:

如果您绝对确定您永远不会导致检查异常出现问题,请捕获该异常并准确注释您不需要处理它的原因。(Sleep 会抛出一个 InterruptedException,除非你真的对它感兴趣,否则它总是可以被忽略,但老实说,这是我通常忽略的唯一情况——即使那样,如果你从来没有得到它,那么记录它的成本是多少?)

如果您不确定,但您可能偶尔会得到它,请捕获并记录堆栈跟踪,以便在它导致问题时可以找到它。同样,只捕获您需要的异常。

如果您看不到任何可以抛出已检查异常的方式,请捕获它并将其作为未检查异常重新抛出。

如果您确切知道是什么导致了异常,捕获它并准确记录原因,如果您非常清楚导致它的原因,那么在这种情况下您实际上不需要堆栈跟踪(并且您可能会提到记录它的类,如果你还没有使用 log4j 什么的。

听起来你的问题属于最后一类,对于这种捕获,永远不要做你写的事情(异常 e),总是做特定的异常,以防抛出一些未经检查的异常(错误的参数,空指针, ...)

更新:这里的主要问题是 Checked Exceptions 不好。它们存在的唯一高度使用的语言是Java。它们在理论上很整洁,但实际上它们会导致这种捕获和隐藏的行为,而未经检查的异常是不会出现的。

很多人评论说,我说有时隐藏它们是可以的。具体来说,我能想到的一种情况是:

try {
    Thread.sleep(1000);
catch (InterruptedException e) {
    // I really don't care if this sleep is interrupted!
}

我想我觉得这种用法没问题的主要原因是因为这种 InterruptedException 的使用首先是对检查异常模式的滥用,它传达的睡眠结果不仅仅是指示异常条件。

拥有以下内容会更有意义:

boolean interrupted=Thread.sleep(1000);

但是当他们第一次创建 Java 时,他们为他们新的检查异常模式感到非常自豪(可以理解,它在概念上非常简洁——只是在实践中失败了)

我无法想象另一种可以接受的情况,所以也许我应该将其列为可以忽略异常的唯一情况

于 2008-10-29T19:49:45.383 回答
6

至少,始终 始终 记录您正在捕获但未采取行动的异常。

无声无息地捕捉到的异常是最糟糕的。

于 2008-10-30T00:32:27.387 回答
3

我个人喜欢您至少记录错误的第二个想法。因为您正在捕获异常,所以理论上可以捕获除 SQL 异常之外的其他内容。我不确定会发生什么或有多罕见(如内存不足异常等),但抑制所有错误对我来说似乎不合适。

如果您想抑制错误,我只会对您知道应该以这种方式处理的非常具体的错误进行处理。

假设情况:如果您的 sql 有一个打开的事务,并且因此关闭连接导致异常,您想抑制该错误怎么办?即使抑制 SQLExceptions 也可能有点危险。

于 2008-10-29T19:51:08.733 回答
1

您必须处理异常。这不是一个坏习惯。想象一下,您在关闭数据库连接之前丢失了网络。它可能会抛出异常。

稀有吗?是的。我想这就是他们所谓的异常,这不是忽略它的理由。请记住,如果它可能失败,它就会失败。

您还应该考虑此时是否可能有一个空连接(它会导致 NullPointerException)。

if (connection != null) {
   try { 
      connection.close(); 
   } catch (SQLException sqle) { 
      logger.log(e.getMessage(), e); 
   }
}
于 2008-10-29T20:02:20.723 回答
1

在理想世界中,您永远不应该对异常不做任何事情,当然,在理想世界中,您也永远不会得到异常 8-)

因此,您必须检查各种选项的影响。

仅记录:数据库操作已全部完成,除了清理资源外无事可做。如果此时发生异常,它很可能对执行的工作没有影响,因此记录错误就足够了。当然,如果在记录过程中发生错误,那么您基本上必须处理实际上并未失败的失败数据库操作。

Empty handler:数据库操作全部完成,除了清理资源,别无他法。如果此时出现异常,很可能对执行的工作没有影响,所以方法成功返回。下一次数据库访问可能会遇到同样的问题,但它应该发生在事务开始时,它会正确地失败,然后得到适当的处理。如果问题已自行解决,则不会有任何迹象表明曾经出现过任何问题。

这是一个非常典型的场景,将 close() 操作放在 finally 块中以确保发生清理,因为我们不希望任何其他故障阻止资源清理。如果没有发生错误,那么当它的操作成功完成时,你的方法不应该失败。在这种情况下,空异常处理是很正常的。

当然意见会有所不同。

于 2008-10-29T21:03:02.817 回答
1

你也可以抛出一个 RuntimeException:

try {
    connection.close();
 } catch(Exception e) {
     throw new RuntimeException(e); 
 }

您不必更改您的方法签名,并且稍后可以使用 Exception.getCause 方法来查找问题的原因。

于 2008-10-30T01:39:10.700 回答
1

请注意,Apache Commons DButils提供了一种closeQuietly()方法,您可以使用该方法来避免使用“冗余”捕获使代码混乱。注意我不提倡吞咽异常,但对于这种close()情况,我认为它通常是可以接受的。

于 2009-03-09T14:26:48.863 回答
0

根据我的经验,忽略异常绝不是一个好主意。相信我,如果您记录了异常,生产支持工程师和分析师会非常感谢您。

此外,如果您使用正确的 Logging 框架,则异常对性能的影响为零或最小。

于 2008-10-29T20:07:59.370 回答
0

如果这是一个“永远不会发生的错误”的情况,那么我将重新抛出一个异常并希望没有人能捕捉到它。
如果这是任何其他情况,我可能会记录它

于 2008-10-30T01:21:55.447 回答
0

如果你能处理它,那么就这样做(如果它是意外的,请记录它)。如果您无法处理它,请正确重新抛出它,以便上面的一些代码可以处理它。

默默地吞下异常是为修复代码的人留下了关键信息。

于 2010-04-04T10:04:58.343 回答
0

在关闭与数据库的连接时处理异常是一种更好的做法。因为,稍后在您的代码中的某个时间点,如果您尝试访问语句或结果集对象,那么它将自动引发异常。所以,最好处理异常。

于 2012-09-22T13:16:37.573 回答