异常与 DAO 模式中的 return 代码

Exception versus return code in DAO pattern

在阅读了很多关于 Java 中异常的滥用以及您应该如何让异常在应用程序的不同层中冒泡的内容之后,我已经到了我不这样做的地步知道我应该如何处理我的应用程序可能存在的潜在错误。

基本上,我有一个网络服务,它使用 DAO 模式来访问我数据库中的数据。所有的数据库操作都可以抛出 SQLException。 从今天开始,我正在使用 try catch 来捕获 SQLException,然后将一个名为 ExceptionDAO 的特定定义的异常抛出,该异常将由 Web 服务处理,以 return 将正确的消息发送给我的网络服务的用户(移动应用程序)。

在阅读了很多关于异常应该是异常的并且不应该在控制流中使用的内容之后,我对我应该如何处理任何错误有了一个复杂的理解:

我也看过 null 模式,但我认为它不太适合这种特殊情况。 我还担心不要向用户提供太多信息,而是提供有用且直截了当的信息。实际上,由网络服务编辑的消息 return 将由移动应用程序使用,然后向最终用户显示消息。

我希望我对我遇到的问题已经足够清楚了,我期待着您的回答!

Return 代码非常老派。理想情况下,您应该在某种事务中进行插入,检查:

  1. 锁定用户名插入

  2. 这个用户名可用吗?

    3a。如果是,插入并解锁

    3b。如果没有,解锁并通知用户

如果这不可能,那么一个 return 对象包装结果(如果成功创建)并响应 Enum 和潜在结果。

Return 代码适用于C,它的特性中缺少异常处理。对于 Java,请使用异常,检查或运行时,这是一个品味问题。

就个人而言,我讨厌检查异常,因为它们用可能永远不会发生的边界情况信息污染了我的方法签名。但也许你想严格遵守 类 的合同,即使是在这种特殊情况下也是如此。如果是这种情况,请使用已检查的异常。否则,只要检测到异常情况(例如未找到实体、实体已存在等),就让您的方法签名保持平静并抛出运行时异常。

请注意 ExceptionDAO 不是一个好听的名字。它似乎是一个处理异常的 dao。也许像 PersistenceException 这样的东西会更好。

除了命名细节外,我认为您的方法是正确的,但并不理想。理想情况下,您不需要在从您的 DAO 调用方法的每个方法内(或在您的 DAO 的每个方法内)为 SQLExceptions 执行 try/catch。相反,持久性异常转换机制 会好得多。 Spring,例如 comes with one by default。 Spring 通过代理每个 DAO 并让其代理围绕每个方法调用执行 try/catch 来实现此目的。然后,具有特定 SQL 错误代码的特定 SQLException 被转换为 Spring 自己的 DataAccessException 层次结构。所以,在上层,你最终会得到一个特定的 DataAccessException,但你不需要在每个方法中都做一个 try/catch

如果您已经在使用 Spring,那么您无事可做,但如果您没有使用它并且有许多 DAO 或许多可能抛出 SQLException 的方法,并且你所有的 DAO 都实现了一个接口,那么可能值得努力实现一个代理,拦截你的 DAO 的所有方法并执行try/catch 在他们身边。然后,在这个拦截器的 catch 块中,您将抛出 ExceptionDAO(请重命名!)消息,该消息取决于原始 SQLException(可能还取决于其 SQL 错误代码,也是)。

这种方法的优点是您可以在程序的单个点中处理所有持久性异常

同样的概念也可以应用于您的 Web 层。您可以创建一个代理来拦截每个方法调用并围绕它执行 try/catch,而不是让端点的每个方法都处理您的 ExceptionDAO(不要忘记重命名它!)。然后您可以从异常中提取消息并将其发送到响应中(或您认为适合处理的任何内容)。同样,这一切都基于 Spring,这一次,基于 Spring MVC Exception Handling 机制。您还可以在这里处理意外异常,即 RuntimeExceptions 并向您的用户提供适当的消息。

优势再次在于,您可以在程序的单个点中处理到达 Web 层的所有异常。

请参阅 Proxy javadocs and this tutorial 以进一步了解 Java 的代理。

我认为你错过了一个重要的选项,即观察者模式。

在你的 DAO 中你可以有这个:

public interface OnExceptionInteractionListener {
    public void onExceptionInteraction(String exceptionMessage);
}

我希望 DAO 是这样的:

public SomeDAO(OnExceptionInteractionListener listener, ...) {
}

我会将 DAO 实例化为

SomeDAO s = new SomeDAO(new OnExceptionInteractionListener() {
  public void onExceptionInteraction(String exceptionMessage) {
  }
}, ...);

因此,如果捕获到异常,则调用 DAO 中的侦听器,下一级将处理它。

这比抛出异常的性能更好,也比 return 代码更好。

有关此的更多信息,您可以查看此答案,对于其他示例:

我没试过,但我希望 lambda expressions 对此也有用,如果您使用 Java8。