我应该检查代码中的数据库约束,还是应该捕获数据库抛出的异常

时间:2009-01-01 19:38:10

标签: database nhibernate exception-handling constraints unique

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


感谢大家的出色表现。

我找到了另一个原因,我应该在代码中验证,而不是等待抛出异常(并被我的代码捕获)。似乎NHibernate只会抛出一个NHibernate.Exceptions.GenericADOException,它在这种情况下对异常的原因没有太多信息。或者我在这里错过了NHibernate的一个方面?

8 个答案:

答案 0 :(得分:14)

答案是:两者兼而有之。

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

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

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

  • 数据库保护自己免受攻击 不正确的更新违反了 限制。如果你发现你有其他的 系统或界面填充 数据库顺着轨道走了 数据库强制执行的约束 意味着什么都被抓住了 约束不会(或至少 不太可能破坏你的系统。

除了最微不足道的案例之外,应用程序和数据库都存在于M:M关系中。应用程序仍应具有相应的数据和业务规则验证,但您仍然不应该计划您的应用程序是数据的唯一客户。在数据仓库工作几年,你会看到具有这种心态的人设计的应用程序的效果。

答案 1 :(得分:4)

如果您的设计是好的(数据库和BL),数据库不应该有任何不会在BL中处理的约束 - 即您不应该使用不一致的数据呈现数据库。但没有什么是完美的。

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

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

答案 2 :(得分:3)

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

<强>理由:

  1. 效果 - 数据库将是 高度优化以执行 约束快速有效 办法。你没有时间 优化你的代码。
  2. 可维护性 - 如果有约束 改变未来,你不会有 修改你的代码,或者你 只需要添加一个新的catch {}。 如果删除约束,则为您 不必触摸您的代码 所有

答案 3 :(得分:2)

如果您要自己检查约束,请在数据访问层中执行此操作。该层之上的任何内容都不应该知道您的数据库或其约束。

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

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:1)

您需要回答的问题是:

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

如果在插入后捕获错误,则没有足够的信息来显示正确的消息(至少以不可知的DB方式)

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

运作良好的方法是:

  • 检查之前提出一个好的 消息
  • 抓住异常并且 提出一个常见的错误消息 (假设这不会发生 的频率)

答案 6 :(得分:0)

就个人而言,我会抓住这个例外。它更简单,需要更少的代码。

答案 7 :(得分:0)

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

我不同意在执行插入之前检查数据库的唯一性,对数据库进行两次往返是不是非常有效,如果你有大量的用户流量,肯定是不可扩展的。