看起来您已经发现对需要关闭的事物(例如 JDBC Statement
)进行正确的异常处理是一件非常痛苦的事情。Java 8 lambdas 在这里可能会有所帮助,但这是 Java 7 中引入的try-with-resources 语句的教科书示例。事实上,该教程有一个 JDBC 示例,尽管它与您的示例有点不同'正试图在这里做。
在我们可以应用 try-with-resources 之前,我们需要仔细查看您的finally
块。preparedStatement != null
首先,在这一点上实际上是不正确的断言。conn.prepareStatement
try 块顶部的语句可以 throw beforeSQLException
被preparedStatement
分配,因此在 finally 块执行时它实际上可能仍然为 null。(大多数人在这里添加一个空检查,并且只在它不为空时关闭该语句。) try-with-resources 语句通过在其 finally-block 负责关闭资源的 try-finally 语句之外初始化资源来避免这个问题.
clearParameters
其次,在断言之后有一个调用。我不认为这是必要的。该语句即将关闭,并且preparedStatement
变量即将超出范围,因此它将变得无法访问并因此被垃圾收集。清除参数应该不会有任何效果。
考虑到这些点,很明显 finally 块的主要职责是关闭语句,处理SQLException
来自关闭操作的任何语句,允许封闭方法正常返回。这几乎就是 try-with-resources 所做的。
重写代码以使用 try-with-resources 给出以下结果:
try (PreparedStatement preparedStatement = conn.prepareStatement(removeFollowersStmt)) {
preparedStatement.setLong(1, Long.parseLong(conversation) );
preparedStatement.setLong(2, Long.parseLong(userId) );
preparedStatement.executeUpdate();
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
没错,整个finally-block都可以丢掉!但是,确切的行为与您的原始代码有些不同。不同之处在于如果一切都通过executeUpdate
成功,但关闭语句会抛出一个SQLException
. 在原始代码中,将打印堆栈跟踪并且该方法将返回true
。
在修改后的代码中,close
调用的异常将被此处的单个 catch 子句捕获,该子句将打印堆栈跟踪并返回false
。我不知道这是否正确。我的印象是,如果关闭语句引发异常,则可能意味着先前执行的更新实际上并未成功。如果是这样,那么返回false
是正确的事情。(但我不是 JDBC 专家。)
这比以前更好,但仍然需要在每个语句执行周围添加 try-catch 样板。你能重用这个结构并传入一个lambda吗?我想是的,但我们必须先做一些准备。该方法将需要一个用于创建 的 SQL 字符串PreparedStatement
和一个负责将参数设置到语句中的 lambda。这里的问题是所有人的二传手PreparedStatement
都可以 throw SQLException
。Java 8 包中的内置函数式接口都没有java.util.function
处理这个问题,所以我们必须创建自己的函数式接口:
interface StatementPreparer {
void prepare(PreparedStatement ps) throws SQLException;
}
现在我们有了这个,让我们编写一个方法来准备一个语句并执行它,处理异常,并返回一个布尔状态:
boolean update(String sql, StatementPreparer sp) {
try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
sp.prepare(preparedStatement);
preparedStatement.executeUpdate();
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
现在在想要执行实际工作的代码中,它可以发出如下调用:
boolean result = update("delete from followers where conv = ? and userid = ?",
preparedStatement -> {
preparedStatement.setLong(1, Long.parseLong(conversation) );
preparedStatement.setLong(2, Long.parseLong(userId) );
});