19

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


感谢大家的大力投入。

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

4

8 回答 8

15

答案是:两者都有。

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

  • 如果您的应用程序中有错误,违反约束将标记一些可能不会被注意到的内容。

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

  • 数据库保护自己免受违反约束的不正确更新。如果您发现您有一些其他系统或接口在跟踪数据库中填充数据库,那么数据库强制执行的约束意味着任何被约束捕获的东西都不会(或至少不太可能)破坏您的系统。

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

于 2009-01-01T19:49:48.087 回答
4

如果您的设计是好的(数据库和 BL),那么数据库不应该有任何在 BL 中不会处理的约束——也就是说,您不应该向数据库提供不一致的数据。但没有什么是完美的。

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

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

于 2009-01-01T22:59:22.213 回答
3

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

原因:

  1. 性能- 数据库将高度优化,以快速有效的方式实施约束。您也没有时间优化代码。
  2. 可维护性- 如果将来约束发生变化,您不必修改代码,或者您可能只需要添加一个新的 catch{}。如果删除了约束,您将根本不必接触您的代码。
于 2009-01-01T19:55:10.807 回答
2

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

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

于 2009-01-01T19:53:29.857 回答
1

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

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

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

于 2009-01-01T19:54:35.097 回答
1

您需要回答的问题是:

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

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

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

一种行之有效的方法是:

  • 检查之前提出一个很好的消息
  • 捕获异常并显示一个常见的错误消息(假设这不会经常发生)
于 2010-01-15T15:06:47.023 回答
0

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

于 2009-01-01T19:52:47.707 回答
0

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

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

于 2009-04-16T15:49:43.167 回答