把正确性交给数据库
约束是数据库层的数据守门人:主键唯一标识一行,唯一键防止重复,非空约束拒绝缺失值,CHECK 限制取值范围,外键保证引用完整性。优点是不依赖应用代码自律,缺点是外键检查会引入额外加锁与争用,在分库分表或高并发写入系统中常改为应用层保证。
基本信息
| 适用 | MySQL 5.7 / 8.0,InnoDB 支持外键与 CHECK(8.0.16+ 才真正生效) |
|---|---|
| 常用约束 | PRIMARY KEY、UNIQUE、NOT NULL、DEFAULT、CHECK、FOREIGN KEY |
| 开关 | FOREIGN_KEY_CHECKS 与 UNIQUE_CHECKS |
| 注意 | 唯一索引也是索引,会参与查询优化 |
外键与约束示例
外键与约束示例
CREATE TABLE order_items (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, # 主键唯一标识
order_id BIGINT UNSIGNED NOT NULL, # 非空约束
sku VARCHAR(64) NOT NULL,
qty INT NOT NULL CHECK (qty > 0), # 取值约束(8.0.16+ 生效)
CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB;
SET FOREIGN_KEY_CHECKS = 0; # 批量导入期间可临时关闭
SET FOREIGN_KEY_CHECKS = 1; # 导入完成必须恢复,避免脏数据长期存在约束类型与影响
| 约束 | 作用 | 代价或注意 |
|---|---|---|
| PRIMARY KEY | 唯一标识且不允许空 | 聚簇索引基础,选择要稳定 |
| UNIQUE | 防重复 | 插入冲突报 1062,也会占用索引空间 |
| NOT NULL / DEFAULT | 拒绝缺失值 | 变更需评估存量数据 |
| CHECK | 限制取值范围 | 8.0.16 起才真正校验,旧版本会被忽略 |
| FOREIGN KEY | 保证引用完整 | 子表写入需检查父表并加锁,争用明显 |
典型使用场景
- 交易类业务用唯一键防止重复下单
- 订单与明细用外键保证引用关系,或改为应用层校验
- 状态字段用 CHECK 限制取值范围
- 批量导入前临时关闭外键检查以提速
- 结构评审:确认关键约束是否缺失导致脏数据
批量导入期间可以临时关闭外键检查提速,但只应限于数据校验阶段,导入完成后必须立即恢复为开启状态。
ON DELETE CASCADE 会随父行删除静默级联删除子行,删除量可能远超预期,设计时要先想清影响范围并确认有备份。
约束变更的做法
- 给存量表加唯一键前先查重复数据,否则 DDL 会直接失败
- 加外键前确认父子表数据一致,避免校验不通过
- 大表结构变更优先评估在线 DDL 或分批方案,先算清锁与资源占用