为什么在数据库中应用约束?放在代码里不是更灵活吗?
我正在阅读一本关于实现数据库的初学者书籍,所以我作为初学者来问这个问题。假设我设计了一个数据库,包括这个实体模型:
entity type | sub-types
----------------+--------------------------------------------
Person | Employee, Student, ...
Student | Graduate, Undergraduate, ...
Employee | Teacher, Administrator, ...
Run Code Online (Sandbox Code Playgroud)
当前限制:
后来我们决定去掉数字 1:如果有一天学院决定Teacher(Employee子类型)也可以Student,在空闲时间参加课程,改变数据库设计要困难得多,可能有数千、数百万、数十亿,数以万计的条目,而不仅仅是更改代码中的逻辑:只是不允许一个人同时注册为学生和员工的部分。
(这是非常不可能的,但我现在想不出其他任何事情。 显然这是可能的)。
为什么我们在数据库设计而不是代码中关心业务规则?
#1:7 年后的一个笔记,一个真实的例子:
我见过一个政府,因为一个错误,发放的 SSN 被复制了:多人,同一个 SSN。那些设计原始数据库的人肯定犯了没有在数据库中应用这种唯一性约束的错误。(后来原始应用程序中的一个错误?多个应用程序使用共享数据库并且不同意在哪里放置、检查和强制执行约束?...)。
这个错误将继续存在于系统中,之后开发的所有系统都依赖于原始系统的数据库,未来很多年。阅读这里的答案,我学会了在数据库中明智地(而不是盲目地)应用所有约束,尽可能多地应用它们,以尽可能好地表示那里的真实物理世界。
Col*_*art 38
因为:
只是一些对我很重要的原因。
Fru*_*ner 35
有些约束最好在数据库中执行,有些则最好在应用程序中执行。
最好在数据库中执行的约束通常存在,因为它们是数据模型结构的基础,例如用于确保产品具有有效category_id.
在应用程序中强制执行的约束可能不是数据模型的基础,例如所有 FooBar 产品都必须是蓝色的——但后来有人可能会决定 FooBar 也可以是黄色的。这是不需要在数据库中的应用程序逻辑,尽管您可以创建一个单独的colours表,并且数据库可以要求产品引用该表中的有效条目。但是,唯一的记录colours具有该值的blue决定仍然来自数据库之外的某个地方。
考虑一下如果您在数据库中没有约束并要求在应用程序中强制执行所有约束会发生什么。如果您有多个应用程序需要处理数据,会发生什么?如果不同的应用程序决定以不同的方式强制执行约束,您的数据会是什么样子?
您的示例显示了在应用程序中而不是在数据库中设置约束可能更有益的情况,但也许初始数据模型过于严格和不灵活存在根本问题?
HLG*_*GEM 20
数据可能会比应用程序代码存活的时间更长。如果规则对数据随着时间的推移有用(例如有助于保持数据完整性的外键约束)至关重要,则它必须在数据库中。否则,您可能会在访问数据库的新应用程序中丢失约束。不仅多个应用程序会访问数据库(包括一些可能没有意识到存在重要数据规则的应用程序),而且其中一些应用程序(例如数据导入或报告应用程序)可能无法使用在主数据输入应用程序中设置的数据层。坦率地说,根据我的经验,应用程序代码中约束中存在错误的可能性要高得多。
在我个人看来(基于 30 多年的数据处理经验和数百个用于许多不同目的的不同数据库的经验),任何没有将约束放入它们所属的数据库中的人最终都会得到糟糕的数据。有时坏数据到无法使用的地步。当您拥有需要满足特定审计标准的财务/监管数据时尤其如此。
Dav*_*dge 18
大多数在数据库外部实现的参照完整性约束都可以被破坏,因此如果您希望数据始终保证完整性,那么您必须在数据库中应用约束。句号,就是这样。
通常,通过数据库读取一致性机制会破坏应用程序级别的约束,通过该机制会话在提交之前无法查看其他会话的数据。
例如,两个会话可以尝试将相同的值插入到旨在唯一的列中。他们既可以检查在同一时间,该值已经不存在,既可以插入自己的价值,并能提交双方。在数据库中实现的唯一约束不会让这种情况发生。
顺便说一下,这对应用程序语言设计者来说并不陌生。阅读Ruby on Rails 指南中的第3.10节唯一性:Active Record Validations and Callbacks
这个助手在对象被保存之前验证属性的值是唯一的。它不会在数据库中创建唯一性约束,因此可能会发生两个不同的数据库连接为您打算唯一的列创建两个具有相同值的记录。为避免这种情况,您必须在数据库中创建唯一索引。
Lei*_*fel 17
数据库强制执行约束的好处:
简单性- 声明约束比声明约束并编写将强制执行该声明的代码要简单得多。
准确性- 您没有编写的代码永远不会有您创建的错误。数据库供应商会花时间确保他们的约束代码准确无误,因此您不必这样做。
速度- 您的应用程序的分布永远不会超过它所基于的数据库。数据库供应商花时间确保他们的约束代码是有效的,因此您不必这样做。数据库本身对数据的访问速度也比应用程序无论多么高效都快。
重用- 您可以从一个平台上的一个应用程序开始,但它可能不会一直这样。如果您需要从不同的操作系统、不同的硬件或语音接口访问数据怎么办?通过在数据库中设置约束,无需为新平台重新编写此代码,也无需为准确性进行调试或为速度进行配置。
完整性- 当数据输入数据库时,应用程序会强制执行约束,并且需要额外的努力来验证旧数据的准确性或操作数据库中已有的数据。
长寿- 您的数据库平台可能会比任何特定应用程序寿命更长。
Gre*_*ker 12
为什么要在服务器上应用约束?因为你不能强迫坏人使用你的客户端。
澄清一下,如果您只在客户端应用程序中进行业务规则处理,那么使用其他工具的人可以连接到数据库服务器并做他们想做的任何事情,而不受任何业务规则和完整性检查的限制。阻止任何人在网络上的任何地方使用任意工具是非常困难的。
如果您在数据库服务器上进行完整性检查,那么每次访问数据的尝试,无论使用何种工具,都将受到您的规则的约束。
Aar*_*and 11
这里有一些很好的答案,并且冒着重复其他想法的风险:
UPDATE直接针对数据库运行一条语句,您的应用程序如何防止无效更改?应用程序中业务规则的另一个问题是重新编译/重新部署可能很困难,特别是对于分布式应用程序,可能不是每个人都能同时获得更新。最后,更改应用程序中的业务规则对违反新规则的已经存在的数据完全没有作用——如果向数据添加新约束,则需要修复数据。在您明确提到的情况下,您突然允许以前不允许的东西,这并不是真正的问题 - 您删除任何强制执行它的约束,无论它存在于何处。在相反的情况下,突然不再允许教师成为学生,您可能需要清理大量数据,无论先前存在何处约束。
小智 9
简短回答...以保持数据完整性(即准确性和有效性)。
一个例外...
如果数据库只是为单个用户存储单个应用程序的数据,例如在大多数 Sqlite 数据库中,它可能不需要约束。事实上,他们通常不这样做,以保持访问时间如此之快,以至于无法衡量。
对于其他一切......
数据库总是为两个主人服务,我称之为editors和users。
编辑者大多将数据放入数据库,一次检索一条或少量记录。他们的主要关注点是快速、准确地访问所有相关数据以及快速、可靠地存储其更改。
用户主要是检索数据,并且最关心快速访问毫无疑问的准确信息。他们经常需要各种计数、聚合和列表,这些计数、聚合和列表过去是在那些标志性的一英尺厚的绿条纸打印输出中生成的,但今天通常会出现在网页上。
数据库开发项目几乎都是在授意下开始了用户,但设计得到由数据输入和记录在-A-时间的需求驱动的编辑。因此,缺乏经验的开发人员通常会通过不在数据库中设置约束来响应对速度(主要是开发速度)的迫切需求。
如果有且仅有一个应用程序曾经打算用来更改的数据整个生命的数据库,并且该应用程序是由一个或少数几个很好的协调个人的发展,那么它可能是合理的依靠确保数据完整性的应用程序。
然而,尽管我们假装可以预测未来,但我们做不到。
生产任何数据库的努力都太有价值了,不能把它扔掉。数据库就像房子一样,会被多次扩展、改变和翻新。即使完全替换,所有数据也会迁移到新数据库,同时保留所有旧的业务规则和关系。
约束在数据库引擎本身中以简明的、声明性的形式实现这些规则和关系,以便于访问它们。如果没有它们,后续的开发人员将不得不通过应用程序来对这些规则进行逆向工程。祝你好运!
顺便说一下,这正是大型机 COBOL 程序员必须做的事情,因为这些海量数据库通常是在我们拥有关系引擎和约束之前创建的。即使迁移到像 IBM 的 DB2 这样的现代系统,约束有时也不会完全实现,因为可能包含在一系列 COBOL“批处理”程序中的旧规则的逻辑可能非常复杂,以至于无法进行转换。相反,可以使用自动化工具将旧的 COBOL 转换为带有新关系引擎接口的新版本,并通过一些调整,保持数据完整性......诉诸法庭,例如,取消数千名他们不应该拥有的房主的赎回权。
除了其他评论...
如果/当您有一个数据库,其中任何给定的表可以由一个或多个应用程序或代码路径更新,那么在数据库中放置适当的约束意味着您的应用程序不会复制“相同”的约束代码。这通过简化维护(如果/当数据模型发生更改时减少要更改的位置数量)并确保无论应用程序更新数据如何都始终如一地应用约束,从而使您受益。
小智 6
就我个人而言,我认为创建和更改约束比创建触发器更容易,例如,这是使用源代码强制执行业务规则的一种方法。
触发器也不太可能是可移植的,因为它们通常是用供应商特定的语言编写的,例如 PL/SQL。
但是,如果约束不能满足您的需求,您始终可以使用触发器来强制执行您的业务规则。
他们应该总是在数据库应用首先是因为,
varchar(5)类型,那么您很有可能为您的特定语言找到一个架构加载 ORM,它将语言类型映射到架构的类型,并组装它自己对大小的约束。DBIx for Perl is one such schema loader; 这是Entity Framework 的另一个。这些加载器的功能各不相同,但它们可以提供的任何功能都是确保应用程序完整性的良好开端,而无需访问数据库。| 归档时间: |
|
| 查看次数: |
8090 次 |
| 最近记录: |