不应强制执行参照完整性的原因之一是性能。因为 Db 必须针对关系验证所有更新,所以它只会让事情变慢,但是执行和不执行的其他优点和缺点是什么?
因为无论如何关系都是在业务逻辑层中维护的,所以它只是让 db 做这些事情变得多余。你对此有什么想法?
不应强制执行参照完整性的原因之一是性能。因为 Db 必须针对关系验证所有更新,所以它只会让事情变慢,但是执行和不执行的其他优点和缺点是什么?
因为无论如何关系都是在业务逻辑层中维护的,所以它只是让 db 做这些事情变得多余。你对此有什么想法?
数据库负责数据。就是这样。时期。
如果没有在数据库中完成参照完整性,那么它就不是完整性。它只是相信人们不会做坏事,在这种情况下,您甚至不应该担心密码保护您的数据:-)
谁说你不会让某人编写他们自己的连接 JDBC 的客户端来完全搞砸数据,尽管你的业务层设计完美且没有错误(它可能不会没有错误的事实完全是另一个问题,要求数据库应该保护自己)。
首先,要让它真正正常工作几乎是不可能的。为了有机会正常工作,您需要将许多级联修改包装为事务,因此当您更改数据库的一部分时,您不会出现不同步的事情,但仍在更新依赖于其他部分的其他内容首先。这意味着本应简单且只了解业务逻辑的代码突然需要了解各种并发问题。
其次,保持它工作几乎是不可能的——每次任何人触及业务逻辑时,他们都需要再次处理那些并发问题。
第三,这使得引用完整性难以理解——将来,当有人想了解您的数据库结构时,他们将不得不从您的业务逻辑中对其进行逆向工程。有了它在数据库中,它是独立的,所以你需要看的只是参照完整性,而不是各种不相关的问题。您有(例如)直接的逻辑链,显示对特定字段的修改将触发什么。至少对于相当多的数据库,可以自动提取该逻辑并将其转换为相当有用的文档(例如,显示依赖关系的树形图)。从 BLL 中提取相同类型的信息更有可能是一个相当严肃的项目。
在另一个方向上肯定有一些要点,以及手工制作所有这些的理由——可伸缩性和性能是最明显的。但是,当/如果你走那条路,你应该知道你为了获得这种表现而放弃了什么。在某些情况下,这是一个值得权衡的选择——但在其他情况下则不然,您需要信息来做出合理的决定。
可以在业务逻辑层中维护关系。除非您可以 100% 毫无疑问地保证您的 BLL 永远不会出现错误,否则您就没有数据完整性。而你不能做出这样的保证。
此外,如果另一个应用程序将访问您的数据库,则不需要遵循(阅读:重新实现,可能以一种微妙的错误方式)BLL 中的规则。 即使您以某种方式设法成为地球上 3 位编写无错误代码的程序员之一,它也可能损坏数据。
同时,数据库对每个人执行相同的规则——当您更新时,数据库执行的规则不太可能被忽视,因为数据库不允许这样做。
听听eBay 的技术研究员 Dan Pritchett讲述为什么某些数据库结构(例如事务和参照完整性)不是教科书可能指出的要求……它归结为数据类型、查询量和业务需求。平衡这些,它将引导你找到务实的解决方案,而不是教条的答案......
但是,不要假设在 BLL 中保持关系会保护您的数据。您不能保证未来的开发人员不会因为“性能”原因或对您的架构缺乏了解而公开绕过 BLL 的新 API……
作为一般规则,问题所基于的性能假设是不正确的。通常,如果您需要强制执行 RI,那么数据库是执行此操作的最有效位置,而不是应用程序 - 否则应用程序必须重新查询更多数据才能在数据库之外验证 RI。
此外,数据库中的 RI 约束对查询优化器很有用,可以使其他查询更高效。应用程序中的完整性约束无法实现这一点。
最后,在每个应用程序中维护完整性约束的成本通常比在一个地方进行一次更昂贵和复杂。
关于数据库应该是验证/控制约束的最终位置这一事实已经说了很多(我完全同意)
如果数据很重要,那么您的应用程序不会是最后一个访问数据库的,也不会是唯一的。
但是关于引用完整性(和其他约束)还有另一个非常重要的事实:它记录了您的数据模型并明确表之间的依赖关系。
就性能而言,在数据库中定义 FK(或其他约束)在某些情况下可以使事情变得更快,因为 DBMS 可以依赖约束并进行适当的优化。
但是 Ingus 上校,如果您在会话中获得了具有 id 的客户,那么您已经探查了数据库!问题是当您写下您的销售订单,但没有将其附加到产品上,因为您没有探索产品。一种或另一种方式,你最终会得到孤立的记录,就像我目前工作的一家非常大的公司一样。我们有没有历史的客户,也有没有客户的历史;从未购买过任何东西的余额未清的客户和向不存在的客户出售的商品——有趣的商业概念——它让一群非常沮丧的支持人员全职工作,试图解决这个问题。将 RI 放在所有东西上并购买一个更大的盒子来解决任何感知到的性能问题会便宜得多。
这取决于数据,如果它的高度事务性数据(例如业务事务)以及不经常更新的地方,那么在数据库中执行业务规则非常重要。但对于其他所有事情,性能影响可能不值得。
paxdiablo 和 dportas 说了什么。还有我的两分钱。还有另外两个考虑。
为了验证新插入的引用完整性,您必须对数据库进行探测以验证引用是否有效。您只是取消了导致您希望在应用程序中强制执行完整性的性能提升。让 DBMS 强制执行参照完整性实际上更快。
除此之外,考虑您有多个应用程序在单个数据库中读取和写入数据的情况。如果您在业务应用程序层中强制执行参照完整性,则必须确保所有应用程序都正确执行操作。否则,一些异常的应用程序可能会存储无效的引用,并且当不同的应用程序使用数据时问题可能会出现。这真是一团糟。最好让 DBMS 为所有应用程序强制执行数据规则。
如果您要维护业务层中的关系,则可以保证几年后您的数据库中将有错误的数据。业务层是最糟糕的地方。
此外,当您用其他东西替换业务层时,您必须重新定义所有这些东西。数据库通常比为它们编写的原始应用程序寿命长很多年,将正确的关系和约束放在它们所属的数据库中。
当您尝试向数据库中插入一条记录但引用完整性失败时会发生什么?你从数据库中得到一个错误。然后您必须更改您的代码,使其不会尝试插入无效数据。为了避免引用完整性错误,您的代码必须知道哪些数据是哪些。因此,参照完整性是没有用的。
Walter Mitty 说:“为了验证新插入的引用完整性,您必须对数据库进行探测以验证引用是否有效。” 叹息……这完全是胡说八道。如果我在会话中有一个客户对象(那是内存,也就是你们中的一些人的 RAM),我知道客户的 ID 并且可以使用它来插入一个 SalesOrder 对象。无需查找客户。
我现在在一个具有严格参照完整性的系统上,并且 Hibernate 用它的粗触手包裹着它。这是我见过的最慢的系统。我没有设计它,如果我有,它会快很多倍并且更容易维护。休眠很烂。