我应该捕获关闭java.sql.Connection时抛出的异常

时间:2008-10-29 19:43:29

标签: java jdbc coding-style

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. 如果不好,我应该如何处理异常。
  4. 评论:

    我知道丢弃异常是邪恶的,但我只是在关闭连接时抛出的异常(而且我已经看到这种情况在这种情况下相当普遍)。

    有人知道Connection.close()什么时候可能扔东西吗?

12 个答案:

答案 0 :(得分:13)

实际上,你所做的是(几乎)最佳实践:-)这是我在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);
    }
  }
}

答案 1 :(得分:12)

总的来说,我已经浪费了几天人们抛弃这样的例外情况。

我建议遵循以下几条基本规则:

如果你绝对确定你永远不会导致检查异常的问题,抓住JUST该异常并准确评论为什么你不需要处理它。 (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时,他们为他们新的检查异常模式感到非常自豪(可以理解的是,它在概念上非常简洁 - 只在实践中失败)

我无法想象另一个可以接受的情况,所以也许我应该将其列为 单例,忽略异常可能是有效的。

答案 2 :(得分:6)

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

在没有最微小的窥视的情况下,悄悄地捕获的异常是最糟糕的。

答案 3 :(得分:3)

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

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

假设情况:如果你的sql有一个打开的事务,并且关闭连接导致了一个exceptino因为那个,你想要抑制那个错误怎么办?即使压制SQLExceptions也可能有点危险。

答案 4 :(得分:1)

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

难得一见吗?是。我想这就是所谓的例外,这不是忽视它的理由。请记住,如果它失败了,它就会失败。

您还应该考虑此时是否可以建立空连接(它会导致NullPointerException)。

if (connection != null) {
   try { 
      connection.close(); 
   } catch (SQLException sqle) { 
      logger.log(e.getMessage(), e); 
   }
}

答案 5 :(得分:1)

在一个理想的世界里,你永远不应该对异常做任何事情,当然,在一个理想的世界里,你永远不会得到例外8 - )

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

仅记录:数据库操作全部完成,除了清理资源外别无选择。如果此时发生异常,则很可能对执行的工作没有影响,因此记录错误应该足够了。当然,如果在日志记录期间发生错误,那么您基本上必须处理实际上没有失败的失败的数据库操作。

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

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

当然意见会有所不同。

答案 6 :(得分:1)

您还可以抛出RuntimeException:

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

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

答案 7 :(得分:1)

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

悄悄吞咽异常会遗漏关键信息,以便该人修复代码。

答案 11 :(得分:0)

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