【问题标题】:Should I check for DB constraints in code or should I catch exceptions thrown by DB我应该检查代码中的 DB 约束还是应该捕获 DB 抛出的异常
【发布时间】:2009-01-01 19:38:10
【问题描述】:

我有一个将数据保存到名为 Jobs 的表中的应用程序。 Jobs 表有一个名为 Name 的列,它有一个 UNIQUE 约束。 Name 列不是 PRIMARY KEY。我想知道在尝试保存/更新新条目之前是否应该自己检查重复条目,或者是否最好等待数据访问层抛出异常。如果它有任何重要性,我正在为这个应用程序使用 NHibernate


感谢大家的宝贵意见。

我发现了另一个原因,为什么我应该在代码中进行验证,而不仅仅是等待抛出异常(并被我的代码捕获)。似乎 NHibernate 只会抛出 NHibernate.Exceptions.GenericADOException ,在这种情况下,关于异常原因的信息不是很丰富。还是我在这里错过了 NHibernate 的一个方面?

【问题讨论】:

    标签: database nhibernate exception-handling constraints unique


    【解决方案1】:

    答案是:两者都有。

    如果您的数据库有约束,它可以保证数据的某些不变量,例如唯一性。这在几个方面有所帮助:

    • 如果您的 申请,违反 约束将标记的东西 否则可能不会被注意到。

    • 数据库的其他用户可以 假设更多关于行为 DBMS 强制执行的数据 不变量。

    • 数据库保护自己免受 不正确的更新违反 约束。如果你发现你有其他的 系统或界面填充 数据库在轨道上, 数据库强制执行的约束 意味着任何被 约束不会(或至少 不太可能)破坏您的系统。

    应用程序和数据库在任何情况下都存在 M:M 关系,但最微不足道的情况除外。应用程序仍应具有适当的数据和业务规则验证,但您仍不应计划将您的应用程序作为数据的唯一客户。在数据仓库工作几年,您会看到具有这种思维方式的人设计的应用程序的效果。

    【讨论】:

      【解决方案2】:

      如果你的设计是好的(数据库和 BL),数据库不应该有任何不能在 BL 中处理的约束 - 即你不应该向数据库提供不一致的数据。但没有什么是完美的。

      我发现,将数据库限制在数据一致性约束中可以让我处理程序代码中的所有 BL 验证,而我遇到数据库异常的唯一情况是可以(并且应该)修复的设计和编码错误。

      在您的情况下,检查名称的唯一性是数据内容验证,在代码中正确处理。这可能会捕获最接近委托点的错误,希望您可以在其中调用更友好的 UI 资源,而不会在抽象之间引入不良耦合。

      【讨论】:

        【解决方案3】:

        我会把这项工作完全交给数据库;您的代码应专注于捕获和正确处理异常。

        原因:

        1. 性能- 数据库将 高度优化以执行 快速高效的约束 方式。你将没有时间 同时优化您的代码。
        2. 可维护性- 如果约束 未来改变,你不会有 修改你的代码,或者你 只需要添加一个新的 catch{}。 如果一个约束被删除,你 不必在 全部。

        【讨论】:

        • 某些应用程序需要准确地告诉用户出了什么问题。如果你想要一个例外,比如“已经有一个名为'Joseph'的用户”或“用户'Bruce Willis'已经使用了登录名'bw'”或其他什么,你不能只在一个catch 处理程序,因为您没有所有信息,或者它太特定于数据库。
        【解决方案4】:

        如果您要自己检查约束,请在数据访问层进行。该层之上的任何内容都不应该了解您的数据库或其约束。

        在大多数情况下,我会说让 DAL 来捕获源自 DB 的异常。但在您的具体情况下,我认为我们正在谈论基本输入验证。在提交整个表单之前,我会选择对数据库进行名称可用性检查调用。

        【讨论】:

          【解决方案5】:

          您绝对应该检查数据访问层抛出的任何异常。检查是否存在具有相同值的记录的问题在于,它需要您锁定表以进行修改,直到您插入新记录以防止竞争条件。

          通常建议检查异常/错误,即使您之前已自行检查过所有内容。几乎总是有一些事情可能出错,或者您在代码中没有考虑到但由数据库强制执行。

          编辑:如果我理解正确的问题,这不是关于约束是否应该由数据库强制执行,而是如何在应用程序代码中处理它。当然,您应该始终在数据库中设置所有约束,以防止不良数据进入您的数据库。

          【讨论】:

          • 是的,你说得对。当我知道无论如何都会抛出异常时,我在问是否可以避免前往数据库检查重复性。
          • 但是要检查你还需要查询数据库,所以你甚至必须发出(至少)两个查询:一个要检查,一个要插入/更新。假设重复很少见,这甚至比尝试插入和捕获异常更昂贵。
          【解决方案6】:

          你需要回答的问题是:

          “我需要向用户展示好消息吗”。示例:已经有一个名为 TestJob1 的作业。 如果答案是,只需捕获错误并显示常见消息 如果答案是,请继续阅读

          如果您在插入后发现错误,则没有足够的信息来呈现正确的消息(至少以不可知的数据库方式)

          另一方面,可能存在竞争条件,您可以同时进行事务尝试插入相同的数据,因此您需要数据库约束

          一种行之有效的方法是:

          • 检查前呈现漂亮 留言
          • 捕获异常并 显示一个常见的错误信息 (假设这不会发生 经常)

          【讨论】:

            【解决方案7】:

            我个人会发现异常。它更简单,需要更少的代码。

            【讨论】:

              【解决方案8】:

              GenericADOException 的内部异常会告诉您数据库操作失败的原因。您可以捕获 OracleException / MSSQLException / [InsertCustomExceptionHere] 并处理来自该消息的错误。如果您想将此返回到前端(假设用户是输入重复数据的用户),您可能希望首先将其包装在自定义异常中,这样您就不会将前端耦合到数据库。您真的不想传递 RDBMS 特定的异常。

              我不同意在插入之前检查数据库的唯一性,两次往返数据库效率不高,如果您有大量用户流量,肯定无法扩展。

              【讨论】:

                猜你喜欢
                • 2011-04-27
                • 1970-01-01
                • 1970-01-01
                • 2012-04-28
                • 1970-01-01
                • 2021-08-20
                • 2015-07-12
                • 2013-05-20
                • 1970-01-01
                相关资源
                最近更新 更多