我经常遇到这样的情况:-
try{
...
stmts
...
}
catch(Exception ex) {
...
stmts
...
} finally {
connection.close // throws an exception
}
最后仍然需要一个 try - catch 块。
克服这个问题的最佳做法是什么?
我经常遇到这样的情况:-
try{
...
stmts
...
}
catch(Exception ex) {
...
stmts
...
} finally {
connection.close // throws an exception
}
最后仍然需要一个 try - catch 块。
克服这个问题的最佳做法是什么?
编写一个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()
)
{
...
}
正如其他人所提到的,静态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) {
...
}
}
}
我通常是这样做的:
try {
try {
..
stmts
...
}
finally {
connection.close():
}
} catch (Exception ex) {
..
stmts
..
}
我通常只在我不使用为我处理这个管道的库时才使用它。
正如Imagist指出的那样,这在技术上与 finally 将在 catch 之前运行不同,但我认为它解决了您试图解决的问题。
Commons-io 也有 closeQuietly() 用于输入和输出流。我一直在使用它。它使您的代码更具可读性。
在 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) {
}
}
}
不要犹豫,再试一次……终于抓住了。
通常,除了记录关闭资源时发生的异常之外,您不想做任何事情,因此它应该真正进入自己的 try/catch 中。但是,这是经常发生的通用代码,所以不要重复自己,并将关闭放在静态方法中(如 Nick Holt 建议的那样),这样您就不会在同一方法中使用两个 try/catch 项,使代码更易于阅读和遵循。
Google Guava 库中还有方便的 Closeables#closeQuitely 方法 - 它可用于任何 Closeable
我们可以先尝试块,然后是最终块,然后再捕获块吗?
只要记住..最后总是用try或catch来执行..