DAO模式中的异常与返回代码

时间:2015-02-21 23:11:19

标签: java web-services exception exception-handling dao

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

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

在阅读了很多关于异常应如何例外并且不应该用于控制流程的内容之后,我已经对我应该如何处理任何错误提出了一个复杂的理解:

  • 使用返回代码处理可能发生的任何事情(例如,用户名已存在),因此,为了符合DAO模式,请将我的业务对象作为参数传递。我还可以使用一个特定的对,它将返回代码+业务对象。然后,Web服务将使用返回代码来显示特定消息。
  • 对我无法预测会发生的任何事情使用已检查的异常,让它们冒泡到Web服务以处理并向用户返回消息。 (例如我无法预测的SQLException:连接中止)
  • 让未经检查的异常冒出来并在这种情况下显示一种404错误。

我也看过零模式,但我认为它并不适合这种特殊情况。 我还担心不向用户提供太多信息,而是直截了当地提供信息。实际上,移动应用程序将使用webservice返回的消息,然后向最终用户显示消息。

我希望我对我遇到的问题足够清楚,并期待你的回答!

3 个答案:

答案 0 :(得分:1)

返回代码适用于C,其功能中缺少异常处理。对于Java,请使用检查或运行时的异常,这是一个品味问题。

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

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

除了命名细节之外,我认为你的方法是正确的,但并不理想。理想情况下,您不需要在每个调用DAO方法(或DAO的每个方法内)的方法中为try/catch执行SQLException。相反,持久性异常转换机制会好得多。例如,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错误代码)。

此方法的优势在于您可以在程序的单个点处理所有持久性异常

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

同样的好处是,您可以在程序的单个点处理到达网络图层的所有异常。

有关Java代理的详细信息,请参阅Proxy javadocsthis tutorial

答案 1 :(得分:1)

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

在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中调用侦听器,然后上一级将处理它。

这比抛出异常更好,而且比返回代码更好。

有关此内容的更多信息,您可以查看此答案,其他示例:https://stackoverflow.com/a/18585099/67566

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

答案 2 :(得分:0)

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

  1. 锁定用户名插入

  2. 此用户名是否可用?

    3A。如果是,请插入和解锁

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

  3. 如果那是不可能的话,那么如果成功创建了结果,那么返回对象将包装结果,并以可能的结果响应Enum。