数据库完整性(Database Integrity)是指数据库中数据在逻辑上的一致性和正确性,它是数据库系统区别于普通文件系统的一个根本性标志。在关系数据库理论体系中,完整性约束是与关系模型、数据操纵语言并列的三大支柱之一。中国计算机技术与软件专业技术资格考试(软考)的数据库系统工程师科目,几乎每一年都会围绕完整性约束设置题目,它横跨上午的选择题和下午的案例分析题,是命题人反复耕耘的一块高频考点。
从标准定义看,数据库完整性指的是数据的正确性、有效性和相容性。正确性要求数据符合现实世界的语义,比如年龄不能是负数,工资不能是零元以下;有效性要求数据必须落在合法的取值范围内,比如性别只能是男或女两个取值;相容性要求同一数据在不同关系或不同副本之间必须保持一致,比如一个员工所在的部门编号,必须真实存在于部门表中。这三者共同构成了完整性约束的完整内涵,任何一方面的缺失都会导致数据库陷入垃圾进、垃圾出的困境。
在关系数据库的教材体系中,完整性约束通常被划分为三类,即实体完整性、参照完整性和用户定义完整性。这三类约束并非并列关系,而是各有其保护对象和实现机制。实体完整性保护的是基本关系中的元组身份,它要求主属性不能取空值;参照完整性保护的是关系之间的引用关系,它要求外键要么为空要么等于被引用表主键的某个值;用户定义完整性则是前两者的补充,它保护的是与应用领域相关的具体业务规则,比如成绩在零到一百分之间,库存数量非负,日期不能晚于当前日期等。这三条防线层层递进,共同构建起关系数据库的数据安全体系。
需要特别强调的是,完整性约束与安全性约束是两回事,这也是命题人最喜欢混淆考生的一个点。完整性约束关注的是数据本身是否符合语义规则,它防止的是不合法的数据被写入数据库,属于数据正确性的范畴;而安全性约束关注的是谁能对数据做什么操作,它防止的是未授权用户对数据的非法访问和破坏,属于数据保护的范畴。前者由完整性约束机制来保证,后者由权限授予、身份认证、审计等安全机制来保证。两者目标不同、手段不同,但在数据库管理系统中又是相辅相成的。理解了这一层区别,很多看似模棱两可的选择题就能迎刃而解。
另一个容易混淆的概念是完整性与一致性。在事务的ACID特性中,一致性(Consistency)指的是事务执行前后数据库都处于一致的状态,事务不能破坏数据库的完整性约束。由此可见,完整性约束实际上是一致性这一事务特性的实现基础和判定依据。事务的原子性、隔离性和持久性,最终都是服务于一致性这一目标的,而一致性归根结底就是完整性约束不被破坏。因此,完整性约束在数据库理论中的位置是根基性的,它是整个事务机制的出发点,也是数据库设计阶段必须优先考虑的要素。
数据库管理系统(DBMS)保证完整性的机制,本质上可以归结为一个核心思想:在数据进入数据库的每一个关键环节设置检查点,一旦发现数据违反约束,就拒绝写入并报错。这个思想贯穿于从数据定义、数据操纵到事务提交的全过程,形成了多层次、多时机的完整性强制体系。
完整性的强制,第一步是在数据库模式定义阶段完成的。当用户通过数据定义语言(DDL)创建表时,可以在表定义中直接声明各种完整性约束,比如在建表语句里指定主键、外键、唯一性约束、检查约束、默认值和非空约束等。这些约束一经定义,就被数据库管理系统存储到系统目录(数据字典)中,成为数据库模式的一部分。此后,无论何时何地执行数据操纵语句,DBMS都会自动查阅这些约束规则,对即将写入的数据进行合法性检查。这种机制的好处在于,约束规则与应用程序代码解耦了,完整性保证不再依赖于每一个应用程序员的自觉,而是由数据库系统统一、强制地执行。
约束检查的时机,是理解完整性机制的关键。不同类型的约束,其检查时机也不同。非空约束和检查约束通常在单条记录插入或更新时即时检查,只要新值不满足条件,语句立即失败。唯一性约束和主键约束,则需要在插入和更新时检查新值是否与表中已有值冲突,这通常依赖数据库系统内部维护的唯一性索引或哈希结构来实现高效的冲突检测。参照完整性约束的检查则更为复杂,它不仅在子表插入或更新外键值时需要检查父表中是否存在对应的主键值,还在父表删除或更新主键值时需要检查子表中是否存在引用该主键的外键记录。这种双向检查,正是参照完整性维护中所谓的级联操作和受限操作的由来。
从判定逻辑看,数据库管理系统对约束的检查遵循一个基本原则:只有在新数据不满足约束条件时才拒绝操作,只要新数据满足全部约束,操作就应当被允许。这个原则在SQL标准中体现为约束的立即检查和延迟检查两种模式。立即检查模式下,每条数据操纵语句执行完毕后,DBMS立即对受影响的约束进行检查,一旦发现违规,语句就回滚。延迟检查模式则允许约束检查推迟到事务提交时才进行,这主要是为了支持某些需要在事务执行过程中暂时打破约束、但最终提交时恢复一致性的业务场景。软考考查的绝大多数场景都默认采用立即检查模式,但考生应当知道延迟检查的存在,因为它是区分约束检查粒度的一个进阶考点。
任何约束的强制执行都是有代价的。每一条完整性约束的存在,都会在数据操纵语句的执行路径上增加一次或多次额外的检查,从而带来一定的性能开销。尤其是参照完整性约束,它在子表和父表之间建立了隐式的关联,任何一方的修改都可能触发对另一方的检查,甚至触发级联的更新或删除。因此,数据库设计者需要在数据正确性和系统性能之间做出权衡。一些高并发的业务系统,有时会选择在应用层实现部分业务规则校验,而将最核心、最不能出错的约束保留在数据库层。但软考考查的重点,恰恰在于让考生理解这种权衡背后的原理,而不是鼓励考生随意放弃数据库层的约束。
三类完整性约束各有其精确定义、实现方式和适用场景,下面逐一展开。这三条防线,构成了关系数据库完整性约束体系的完整骨架,也是软考数据库系统工程师科目中分值最密集、最容易出错的部分。
实体完整性的定义是:若属性(或属性组)A是基本关系R的主属性,则A不能取空值。所谓主属性,是指包含在任何一个候选键中的属性。理解实体完整性的关键,在于理解关系模型中元组身份的唯一标识机制。在关系模型中,元组是现实世界实体的抽象,而主键则是元组的身份标识。如果主键取空值,就意味着存在一个无法被唯一识别的元组,这在逻辑上是不可接受的,因为空值代表未知或不存在,一个未知身份实体在关系表中是无法被引用的。
实体完整性的实现,是通过主键约束(PRIMARY KEY)来完成的。主键约束隐含了两层含义:一是唯一性,即主键值在表中必须唯一;二是非空性,即主键值不允许取空值。在实现层面,主键的唯一性依赖数据库系统自动建立的唯一性索引来保证,当插入或更新操作试图产生重复主键值时,系统通过索引快速定位冲突并拒绝操作;非空性则通过约束检查在写入前拦截空值。这种索引加检查的双重机制,使得主键成为关系表中查询效率最高、身份最可靠的标识列,这也是为什么数据库设计的第一条经验法则就是为每张表设定主键。数据库系统在定义主键时会自动创建唯一索引,同时强制主键列的非空属性。需要注意的是,一个关系只能有一个主键,但候选键可以有多个,未被选作主键的候选键可以定义为唯一性约束。此外,复合主键是由多个属性共同组成的主键,复合主键中的每一个属性都是主属性,都不能取空值,这是实体完整性在复合主键场景下的直接推论,也是命题人常设的陷阱点。
参照完整性的定义是:若属性(或属性组)F是基本关系R的外键,它与基本关系S的主键Ks相对应,则对于R中的每个元组,F上的取值要么为空值,要么等于S中某个元组的主键值。通俗地说,外键指向的父表主键值必须真实存在,或者外键为空。空值的含义是暂时尚未确定引用对象,这在某些业务场景下是允许的,比如一个新入职但尚未分配部门的员工,其部门编号可以为空。
参照完整性的实现,是通过外键约束(FOREIGN KEY ... REFERENCES ...)来完成的。外键约束维
本篇完!