跳到主要内容
约 3 分钟3 张卡

数据约束

数据约束限制数据库允许保存的状态。本文负责 MySQL 8.0 InnoDB 的唯一、非空、CHECK 和外键。

1. 面试核心​

先记住这几条,再读正文
  • 主键与唯一性。 主键唯一且非空,普通唯一索引允许多个 NULL。卡 · NULL 与 CHECK
  • 并发约束。 唯一约束在写入时拒绝重复值。应用预查与插入之间仍有并发窗口,因此预查不能替代数据库约束。卡 · 面试核心
  • CHECK 与 NULL。 MySQL 8.0.16 起执行 CHECK,表达式为 TRUE 或 UNKNOWN 时通过。卡 · NULL 与 CHECK
  • 外键动作。 InnoDB 外键即时检查引用关系,NO ACTION 等价于 RESTRICT。卡 · 外键动作与检查时机

2. 表级规则​

下表要求邮箱非空且唯一,余额非空且非负。

CREATE TABLE accounts (
id BIGINT PRIMARY KEY,
email VARCHAR(200) NOT NULL UNIQUE,
balance DECIMAL(12,2) NOT NULL,
CHECK (balance >= 0)
) ENGINE=InnoDB;

重复邮箱违反 UNIQUE,空邮箱违反 NOT NULL。负余额违反 CHECK。

MySQL 8.0.16 起支持执行 CHECK 约束。更早版本会解析部分 CHECK 语法,但忽略检查。8.0.16 起还允许声明 NOT ENFORCED。本例省略该选项,因此实际执行检查。

3. NULL 与 CHECK​

MySQL 唯一索引允许多个 NULL。联合唯一键中有 NULL 时,也允许相同的含空组合。需要完整业务值时,应将各组成列声明为 NOT NULL。

CHECK 只拒绝结果为 FALSE 的行。balance=NULL 时,balance>=0 得到 UNKNOWN。单独的 CHECK 因而允许该行。NOT NULL 才负责拒绝空余额。

默认值只在省略列或使用 DEFAULT 时提供取值。它与非空约束承担不同职责。

4. 并发与引用完整性​

两个请求可同时查询到“邮箱不存在”。查询结束后,其他事务仍可插入该邮箱。唯一约束在实际写入时仲裁冲突。应用应返回明确结果,或按幂等键读取已有记录。

外键验证父记录是否存在。客户是否有下单资格、订单总额是否正确,还需业务规则。跨语句修改的提交边界见数据库事务。

5. 外键动作与检查时机​

外键可为父记录的删除或键更新指定动作。

动作子表存在引用时的行为
RESTRICT / NO ACTIONInnoDB 立即拒绝父记录变更。
CASCADE将删除或键更新传播到子表。
SET NULL将子表外键列置空,要求这些列可空。

InnoDB 即时检查外键。事务中先插子行、后插父行,第一步就会失败。可空外键取 NULL 时,无需匹配父记录。

CREATE TABLE account_items (
id BIGINT PRIMARY KEY,
account_id BIGINT NOT NULL,
FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE RESTRICT
) ENGINE=InnoDB;

已有明细引用账户时,删除账户会被拒绝。外键列需要以同序前缀建立索引。子表缺少该索引时,InnoDB 自动创建。父表使用主键或唯一键作为引用目标。

6. 使用边界​

文本唯一性受排序规则影响。忽略大小写的排序规则会把部分大小写变体视为相同。邮箱等业务标识需先明确比较规则。

数据库约束统一保护所有写入入口。应用校验用于提前反馈错误,仍需处理数据库约束异常。

7 · 面试题卡片​

本页题目与参考回答

7.1 应用已经检查邮箱未被使用,为什么数据库还需要唯一约束?​

考察重点:检查与写入之间的并发窗口,以及唯一、非空和排序规则的组合。

相关内容:面试核心、表级规则、使用边界。

参考回答

应用预查与插入之间存在并发窗口。

两个请求可同时通过检查,再尝试写入相同邮箱。唯一约束在写入时拒绝重复值。邮箱必须有值时,还需 NOT NULL。文本比较则按列的排序规则进行。

7.2 CHECK(balance >= 0) 能拒绝 NULL 吗,唯一索引又如何处理 NULL?​

考察重点:三值逻辑、非空与唯一性。

相关内容:NULL 与 CHECK。

参考回答

CHECK 允许 UNKNOWN,因此空余额能通过该表达式。

要拒绝 NULL,需另加 NOT NULL。MySQL 唯一索引允许多个 NULL。完整且唯一的业务值需要组合 UNIQUE 和 NOT NULL。

7.3 InnoDB 外键的 RESTRICT、CASCADE、SET NULL 有何区别?​

考察重点:引用动作、可空性和即时检查。

相关内容:外键动作与检查时机。

参考回答

RESTRICT 拒绝仍被引用的父记录变更。

CASCADE 将相应删除或更新传播到子表。SET NULL 将子表引用列置空,要求该列可空。InnoDB 即时检查外键,NO ACTION 与 RESTRICT 相同。

8. 参考资料​