【问题标题】:Better way for DB exception handling in javajava中数据库异常处理的更好方法
【发布时间】:2012-09-19 09:49:26
【问题描述】:

哪种情况更好:ErrorCode 还是 Exception?

我曾经见过这两种错误处理技术。我不知道每种技术的优缺点。

public void doOperation(Data data) throws MyException {
    try {
        // do DB operation
    } catch (SQLException e) {
        /* It can be ChildRecordFoundException, ParentRecordNotFoundException
         * NullValueFoundException, DuplicateException, etc..
         */
        throw translateException(e);
    }
}

public void doOperation(Data data) throws MyException {
    try {
        // do DB operation
    } catch (SQLException e) {
        /* It can be "CHILD_RECORD_FOUND, "PARENT_RECORD_NOT_FOUND"
         * "NULL_VALUE_FOUND", "DUPLICATE_VALUE_FOUND", etc..
         */
        String errorCode = getErrorCode(e);
        MyException exc = new MyException();
        exc.setErrorCode(errorCode);
        throw exc;
    }
}

对于第二种方法,错误代码检索表单配置文件。我们可以在SQL Vender Code的基础上添加Error Code

SQL_ERROR_CODE.properties

#MySQL Database
1062=DUPLICATE_KEY_FOUND
1216=CHILD_RECORD_FOUND
1217=PARENT_RECORD_NOT_FOUND
1048=NULL_VALUE_FOUND
1205=RECORD_HAS_BEEN_LOCKED

方法 1 的调用者客户端

    try {

    } catch(MyException e) {
        if(e instanceof ChildRecordFoundException) {
            showMessage(...);
        } else if(e instanceof ParentRecordNotFoundException) {
            showMessage(...);
        } else if(e instanceof NullValueFoundException) {
            showMessage(...);
        } else if(e instanceof DuplicateException) {
            showMessage(...);
        }
    }

方法 2 的调用者客户端

    try {

    } catch(MyException e) {
        if(e.getErrorCode().equals("CHILD_RECORD_FOUND")) {
            showMessage(...);
        } else if(e.getErrorCode().equals("PARENT_RECORD_NOT_FOUND") {
            showMessage(...);
        } else if(e.getErrorCode().equals("NULL_VALUE_FOUND") {
            showMessage(...);
        } else if(e.getErrorCode().equals("DUPLICATE_VALUE_FOUND") {
            showMessage(...);
        }
    }

【问题讨论】:

    标签: java database jdbc


    【解决方案1】:

    我推荐使用 Spring 的JDBCTemplate。它将大多数现有数据库的异常转换为特定的未经检查的异常,例如DataIntegrityViolationException。它还将在消息中包含原始 SQL 错误。

    【讨论】:

      【解决方案2】:

      奇怪的问题,因为这两种方法都做同样的事情:它们将已检查的 SqlException 转换为似乎未检查的不同异常。所以第一个更好,因为它把它变成了一个方法。

      两者都留下一些问题要问:

      • 是否有一些基础设施可以进行这种转换(另一个答案中提到了 Spring 模板)

      • 你真的想要检查异常吗,在我看来它们几乎不值得麻烦。

      • 谁在真正处理异常,它是否获得了所有需要的信息?我通常会期望一些有关在 MyException 内部失败的事务的其他信息,例如:我们尝试做什么? (例如更新业务对象);在什么样的物体上? (例如一个人);我们/用户如何识别对象(例如 person.id + person.lastname + person.firstname)。如果您想生成日志/错误消息来告诉您或您的用户不仅仅是“糟糕,出了点问题”,您将需要此类信息

      • 为什么 MyException 是可变的(至少在第二个示例中)

      【讨论】:

        【解决方案3】:

        比任何一个更好的设计是通过扩展 RuntimeException 使您的自定义异常不被选中。

        我希望您的异常能够包装第一个异常,因此以这种方式编码也会更好:

        MyException exception = new MyException(e); // wrap it.
        

        如果您这样做,则首选第二个。信息越多越好。

        【讨论】:

        • 为什么RuntimeException 会更好?任何使用此代码的开发人员都会在异常发生时发现异常(可能在生产时)。
        • C# 已将惯用语从未经检查的异常转变为检查的异常。 Spring 框架完全符合您的要求,除了 12 年前的情况要好得多。他们使用未经检查的异常。
        • 为什么你认为,第二种方法保留了更多信息?所有信息都来自第一个示例中作为参数传递的异常。
        • 我知道 Java 中的 SQLException 是一个受检异常,它明确保留了供应商 SQL 错误代码——这是其他受检异常所没有的。我假设第二个是本着这种精神。
        【解决方案4】:

        恕我直言,这取决于您的代码与 SQL 的耦合程度。

        如果方法是总是 (*1) 与 SQL 结合,我只需声明并重新抛出 SQLException(在清理/关闭资源之后)。支持 SQL 的上层方法会在他们认为合适的时候对其进行处理(也许他们需要所有的细节,也许他们不需要)。

        如果将来某个时候您可以更改另一个不使用 SQL 的方法,那么我会选择第二个选项。

        (1):对这个假设要特别悲观:“我认为我们不会改变”应该解释为“我们可能会想要改变”。 “我们不会改变”的意思是“无论如何,如果不破坏许多其他方法,我们就无法改变”。

        【讨论】:

          【解决方案5】:

          catch 例外的方式会有所不同。在第一种情况下,您只需 catch 异常,您就知道错误是什么。在第二种情况下,您必须catch 异常并检查代码以查看错误是什么。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-06-12
            • 1970-01-01
            • 1970-01-01
            • 2015-05-21
            • 2015-09-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多