32

我经常遇到这样的情况:-

try{ 
     ...
     stmts
     ...
} 
catch(Exception ex) {
     ... 
     stmts
     ... 
} finally {
     connection.close // throws an exception
}

最后仍然需要一个 try - catch 块。

克服这个问题的最佳做法是什么?

4

10 回答 10

26

编写一个SQLUtils包含static closeQuietly捕获和记录此类异常的方法的类,然后酌情使用。

你最终会得到这样的东西:

public class SQLUtils 
{
  private static Log log = LogFactory.getLog(SQLUtils.class);

  public static void closeQuietly(Connection connection)
  {
    try
    {
      if (connection != null)
      {
        connection.close();
      }
    }
    catch (SQLExcetpion e)
    {
      log.error("An error occurred closing connection.", e);
    }
  }

  public static void closeQuietly(Statement statement)
  {
    try
    {
      if (statement!= null)
      {
        statement.close();
      }
    }
    catch (SQLExcetpion e)
    {
      log.error("An error occurred closing statement.", e);
    }
  }

  public static void closeQuietly(ResultSet resultSet)
  {
    try
    {
      if (resultSet!= null)
      {
        resultSet.close();
      }
    }
    catch (SQLExcetpion e)
    {
      log.error("An error occurred closing result set.", e);
    }
  }
}

您的客户端代码将类似于:

Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try 
{
  connection = getConnection();
  statement = connection.prepareStatement(...);
  resultSet = statement.executeQuery();

  ...
}
finally
{
  SQLUtils.closeQuietly(resultSet);
  SQLUtils.closeQuietly(statment);
  SQLUtils.closeQuietly(connection);
}

更新:从 Java 7 开始,各种 JDBC 接口都得到了扩展java.lang.AutoCloseable,虽然上面的代码回答了原始问题,但如果您直接针对 JDBC API 编写代码,现在可以对其进行结构化:

try (
  Connection connection = getConnection();
  PreparedStatement statement = connection.prepareStatement(...);
  ResultSet resultSet = statement.executeQuery()
)
{
  ...
}
于 2009-08-26T16:06:05.597 回答
12

正如其他人所提到的,静态closeQuietly实用程序是要走的路。要添加的一件事-如果您身处这个世界java.io而不是java.sql那么有一个有用的接口可以用于此目的-java.io.Closeable

所有的数据源和接收器都java.io实现了这个接口——所有的流、通道、写入器和读取器。这样,您可以创建一个实用程序来处理相同的“close() 异常”问题,而无需许多重载版本。

例如

public class IoUtils {

  public static closeQuietly (Closeable closeable) {
    try {
      closeable.close();
    } catch (IOException logAndContinue) {
      ...
    }
  }

}
于 2009-08-26T17:05:19.770 回答
10

我通常是这样做的:

try {
    try {
        ..
        stmts
        ...
    }
    finally {
       connection.close():
    }
} catch (Exception ex) {
     ..
     stmts
     ..    
}

我通常只在我不使用为我处理这个管道的库时才使用它。

正如Imagist指出的那样,这在技术上与 finally 将在 catch 之前运行不同,但我认为它解决了您试图解决的问题。

于 2009-08-26T16:06:03.820 回答
4

Commons-io 也有 closeQuietly() 用于输入和输出流。我一直在使用它。它使您的代码更具可读性。

于 2009-08-26T16:40:59.507 回答
2

在 Java 10 中,您可以编写:

public void java10() throws SQLException {
    try (var connection = Connections.openConnection();
         var callableStatement = connection.prepareCall("my_call");
         var resultSet = callableStatement.executeQuery()) {

        while (resultSet.next()) {
            var value = resultSet.getString(1);
            System.out.println(value);
        }
    }
}

在 Java 7、8 和 9 中,您可以编写:

public void java7() throws SQLException {
    try (Connection connection = Connections.openConnection();
         CallableStatement callableStatement = connection.prepareCall("my_call");
         ResultSet resultSet = callableStatement.executeQuery()) {

        while (resultSet.next()) {
            String value = resultSet.getString(1);
            System.out.println(value);
        }
    }
}

在 Java 6 中,您需要编写所有这些行:

public void java6() throws SQLException {
    Connection connection = Connections.openConnection();
    try {
        CallableStatement callableStatement = connection.prepareCall("my_call");
        try {
            ResultSet resultSet = callableStatement.executeQuery();
            try {
                while (resultSet.next()) {
                    String value = resultSet.getString(1);
                    System.out.println(value);
                }
            } finally {
                try {
                    resultSet.close();
                } catch (Exception ignored) {
                }
            }
        } finally {
            try {
                callableStatement.close();
            } catch (Exception ignored) {
            }
        }
    } finally {
        try {
            connection.close();
        } catch (Exception ignored) {
        }
    }
}
于 2014-12-10T15:05:06.437 回答
1

不要犹豫,再试一次……终于抓住了。

于 2009-08-26T16:06:25.440 回答
0

通常,除了记录关闭资源时发生的异常之外,您不想做任何事情,因此它应该真正进入自己的 try/catch 中。但是,这是经常发生的通用代码,所以不要重复自己,并将关闭放在静态方法中(如 Nick Holt 建议的那样),这样您就不会在同一方法中使用两个 try/catch 项,使代码更易于阅读和遵循。

于 2009-08-26T16:39:12.007 回答
0

Google Guava 库中还有方便的 Closeables#closeQuitely 方法 - 它可用于任何 Closeable

于 2013-03-22T13:45:34.290 回答
0

我们可以先尝试块,然后是最终块,然后再捕获块吗?

于 2014-01-23T18:35:45.327 回答
-1

只要记住..最后总是用try或catch来执行..

于 2009-08-26T16:26:06.620 回答