21

谁能想到一个合理的原因为什么SQLException是一个检查异常?

是的,查询中可能存在语法错误
是的,连接可能已断开
是的,可能存在权限问题
等等等等等等等等等等

但几乎 100% 的时间(一旦你在生产中运行),没有任何问题。

如果出现问题,调用代码无法进行任何恢复,因此应该取消选中

检查会在整个代码中创建大量敷衍的try catch块,任何参与过使用 JDBC 的项目的人都会证明这一点。代码混乱很严重。

由于 SQL 的深奥性,你可能会得到一个 SQLException 的无数原因及其复杂性意味着你基本上无法恢复,除非异常是由临时网络问题引起的,但即使在同步调用中,你还是沉没了因为你不能无限期地等待网络问题得到解决,所以你将不得不让交易失败。

通常,调用 SQL 如下所示:

try {
    // make some SQL call(s)
} catch {SQLException e) { 
    // log the exception
    return; // and give up
}

这样的代码没有任何价值。您无法采取任何合理的措施来恢复。您不妨让运行时异常冒泡——即 SQLException 应该是运行时(未经检查的)异常。

4

4 回答 4

3

几乎 100% 的时间没有任何问题- 这仅限于您自己的观察,而与其他系统无关。世界各地存在各种具有各种瓶颈的计算机系统。您的成功率几乎是 100%。其他人必须处理低得多的百分比。

常见的误解是考虑按其发生频率引入/删除已检查异常。已检查的异常用作通信渠道。如您所知,每个方法都有其公共接口。这样,方法告诉我们它接受哪些参数以及它的主体中的代码的结果是什么。

当当前正在运行的方法无法保持其承诺(例如返回值)时,它需要一种方法来告诉另一个方法出现问题并且它无法执行预期的操作。但是怎么做呢?将消息作为返回值发送是行不通的,调用方法几乎没有机会区分正确的值和错误消息。并不是说某些方法具有 void 作为返回值。那么,当您无法遵守方法接口定义的承诺时,您会怎么做?好吧,你抛出一个异常(发送消息)。

如果您期望 ResultSet 并且没有建立与您的数据库的连接,您应该怎么做?返回空结果集?不,这告诉我们数据库是空的。返回空?好吧,这只代表了问题,并使查找原因不清楚。

您可以使用该空结果集并将其作为对另一个数据库的另一个查询的一部分,从而使其不一致。

如果没有 SQLException,即使是一个错误也可能导致数据不一致。

于 2013-05-14T13:21:01.657 回答
2

一个原因是方法应该抛出与方法所做的抽象级别一致的异常。

因此,从数据库加载信息的方法不应引发 a SQLException,而应引发 aResourceNotFoundException或 a ResourceUnavailableException

进行SQLException检查是一种强制开发人员捕获异常并将其包装在这个新抽象级别中的方法。

这个论点取自 Joshua Bloch 的 Effective Java Second Edition(第 61 条:抛出适合抽象的异常)。

于 2013-05-14T13:07:32.410 回答
2

有几种方法可以解决已检查与未检查的困境。检查调用代码是否可以从异常中恢复是一种方法,但是,我同意这种方法并不能解释为什么SQLExcption是已检查异常。

另一个由 Martin Fowler 在他的巨著“重构”中提供的建议验证是否是调用或被调用方法的责任来进行可能导致异常的检查。

如果调用方方法应该在调用被调用方法之前执行检查(例如,确保参数不为空),那么如果没有进行此检查,那么显然是一个编程错误,然后被调用方法应该抛出一个未经检查的异常。

现在如果检查是被调用方法的责任,因为只有这个方法才能知道如何执行这种检查,那么应该检查从被调用方法抛出的异常。

如果SQLException我认为只有这个类可以知道:

  • 查询中存在语法错误,因为这取决于数据库
  • 连接已断开
  • 存在权限问题
于 2013-05-14T12:59:02.967 回答
1

捕获异常使我们能够从异常情况中恢复,这是真的,但它们也允许我们做其他事情。

您无法从 SQLException 中恢复,因为您无法在运行时解决问题,但您可以做一些有用的事情:

  • 记录调试信息的异常
  • 回滚事务

您始终可以在更高级别(或更低级别,取决于视角)记录异常,但在调试时和查看代码时都会丢失一些语义价值。

如果您执行以下操作:

try { ... }
catch(SQLException e) 
{ 
    SomeLogger.log(...);
    rollback();
    throw e;
}

稍后再回到这段代码,您会立即意识到 try 中的代码可能会失败,而无需在心里解析代码以确定它是否会失败。

您可以做的另一件事是确保已释放所有数据库资源,但我不确定这是否会立即发生。

于 2013-05-14T13:38:12.117 回答