外键(Foreign Key)详解
外键是关系数据库中一个非常核心的概念——说它是表与表之间的“纽带”也不为过。简单来说,它在数据库层面强制规定了两个表之间的关联规则,确保数据不会“乱跑”。下面我们就来系统地拆解一下外键的方方面面。
基本概念
外键是一个表中的字段(或者一组字段),它引用了另一个表的主键或唯一键。目的只有一个:建立和强制两张表之间的关联关系。
主要特性
- 参照完整性:外键的取值要么是NULL,要么必须存在于被引用表的主键中——这就堵死了“无中生有”的数据。
- 级联操作:可以定义当父表记录被更新或删除时,子表该如何自动响应(级联更新、级联删除等)。
- 关系建立:明确了哪张表是主表、哪张是子表,以及它们通过什么字段关联。

如图所示:这张图解释了主表与父表的关系——具有外键的表称为子表(也称从表),被引用的表称为父表(也称主表)。
语法示例
CREATE TABLE 订单 (
订单ID INT PRIMARY KEY,
客户ID INT,
订单日期 DATE,
FOREIGN KEY (客户ID) REFERENCES 客户(客户ID)
);
命名解释
外键约束的名字通常有讲究,下面把这个命名拆开看。
1. CONSTRAINT fk_order_user
- 意思:创建一个名为
fk_order_user的约束。 CONSTRAINT就是“约束”的意思。- 命名规范通常是
fk_子表_主表,这里就是 订单表 关联 用户表。
作用:给规则起个名字,方便后续按名删除或修改。
2. FOREIGN KEY (user_id)
- 意思:在当前表(子表/订单表)中,
user_id这个字段被标记为外键。 - 外键就是“用来去找另一张表”的字段。
作用:告诉数据库——这个 user_id 不是普通字段,它要关联另一张表。
3. REFERENCES user(id)
- 意思:这个外键引用的是主表
user里的id字段。 REFERENCES就是“参考、关联、引用”的意思。
作用:订单表的 user_id 必须是用户表 id 里已经存在的值,不能随便填,不能填一个不存在的用户ID。
三句话总结(背会就懂)
- CONSTRAINT 名字:给这条关联规则起个名。
- FOREIGN KEY (字段):子表里哪个字段要做关联。
- REFERENCES 表 (字段):关联到主表的哪个字段。
添加外键
外键可以在建表时定义,也可以用 ALTER TABLE 在后期添加。添加外键就是为数据库补上一条“关系契约”。
语法格式
ALTER TABLE 子表名称 ADD CONSTRAINT 外键约束名称 FOREIGN KEY (子表字段) REFERENCES 父表名称(父表字段);
详细步骤
- 确定关系:先搞清楚哪张是父表(被引用表),哪张是子表(引用表),确定关联字段。
- 创建外键约束:用
ALTER TABLE修改子表,指定约束名(可选但推荐),指明子表外键字段,用REFERENCES指向父表及其主键。 - 可选参数:可以加上
ON DELETE和ON UPDATE来定义级联行为。CASCADE:级联删除/更新子表相关记录。SET NULL:将子表相关记录的外键设为 NULL。RESTRICT/NO ACTION:阻止父表操作(默认)。
示例场景
假设有两个表:
departments(部门表):包含 dept_id(主键)、dept_name 等字段。employees(员工表):包含 emp_id、emp_name、dept_id 等字段。
为员工表添加指向部门表的外键:
ALTER TABLE employees ADD CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES departments(dept_id) ON DELETE CASCADE ON UPDATE CASCADE;
注意事项
- 父表关联字段必须是主键或唯一键。
- 子表和父表字段数据类型必须完全匹配。
- 添加外键前要确保现有数据满足约束条件,否则会报错。
- 外键会影响数据库写入性能,需合理设计。
- 在大型表上添加外键可能花费较长时间。
应用场景
- 维护数据完整性:防止无效数据插入。
- 实现表间关联查询。
- 自动级联更新或删除相关记录。
- 建立一对多或多对一关系。
删除外键
如果不再需要外键约束,可以用 ALTER TABLE ... DROP FOREIGN KEY 来移除:
ALTER TABLE 表名 DROP FOREIGN KEY 外键约束名称;

这张图展示的是 MySQL 外键在 ON DELETE 和 ON UPDATE 时的五种约束行为。下面逐个拆解用法、区别和适用场景。
一、核心概念
这些行为定义在子表的外键上,用来规定:当父表的主键或唯一键被删除或更新时,子表该如何响应。
二、逐个解释与用法
1. NO ACTION / RESTRICT
- 作用:如果子表有记录引用父表记录,则禁止父表删除/更新,直接报错。
- 区别:在 MySQL InnoDB 引擎下,两者行为完全一样,都是“限制操作”。
- 用法示例
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE RESTRICT ON UPDATE NO ACTION;
- 适用场景:订单表引用用户表时,不允许删除有订单的用户。
2. CASCADE(级联)
- 作用:父表删除/更新时,子表里对应的记录也一起删除/更新。
- 用法示例
FOREIGN KEY (order_id) REFERENCES order(id) ON DELETE CASCADE ON UPDATE CASCADE;
- 适用场景:订单明细表引用订单表——删除订单时,自动删除该订单的所有明细。
3. SET NULL
- 作用:父表删除时,子表外键字段会被设为
NULL。 - 前提:外键字段必须允许为
NULL。 - 用法示例
FOREIGN KEY (manager_id) REFERENCES employee(id) ON DELETE SET NULL;
- 适用场景:部门表引用员工表(manager_id)——员工离职时,部门经理字段自动置空,而不是删除部门。
4. SET DEFAULT
- 作用:父表变更时,子表外键字段被设置为预设的默认值。
- 注意:MySQL 的 InnoDB 引擎不支持,只有部分数据库(如 PostgreSQL)支持。在 MySQL 中不要用,否则报错。
三、关键对比表
| 行为 | 父表删除/更新时 | 子表的反应 | 限制条件 |
|---|---|---|---|
NO ACTION / RESTRICT |
禁止父表操作 | 不做任何变化 | - |
CASCADE |
允许父表操作 | 同步删除/更新子表对应记录 | - |
SET NULL |
允许父表删除 | 子表外键设为 NULL |
外键字段允许为 NULL |
SET DEFAULT |
允许父表操作 | 子表外键设为默认值 | InnoDB 不支持 |
四、实际使用建议
- 优先用
RESTRICT/NO ACTION:这是最安全的默认行为,能防止误删父表数据。 CASCADE慎用:自动删除子表数据容易造成意外丢失,只在明确需要级联的场景(如订单-订单明细)使用。SET NULL要注意空值:业务逻辑要能处理外键为 NULL 的情况,避免后续查询报错。- 不要碰
SET DEFAULT:MySQL InnoDB 不支持,写了也没用。
常见应用场景
- 一对多关系:客户与订单。
- 多对多关系:通过中间表实现。
- 自引用关系:员工表中的经理也是员工。
注意事项
- 外键列和被引用列必须具有相同的数据类型。
- 外键约束会影响数据库写入性能。
- 删除或更新被引用表记录时,必须考虑外键约束的影响。
高级用法
- 复合外键:由多个列组成的外键。
- 延迟约束检查:在事务结束时才检查约束(部分数据库支持)。
- 禁用外键约束:在特殊情况下临时禁用,但需谨慎。
外键是维护数据库完整性的重要机制,合理使用可以确保数据的一致性和有效性。下面是常见的面试真题,一并附上。
外键面试真题(附参考答案)
1. 什么是外键?有什么作用?
参考答案
外键(Foreign Key)用于建立表与表之间的关联关系。主要作用:保证数据一致性、防止脏数据、实现表关系(如一对多)。例如:学生表中的 class_id 引用班级表中的 id。
2. 外键和主键有什么区别?
参考答案
| 主键 | 外键 |
|---|---|
| 唯一标识记录 | 建立表关系 |
| 不允许重复 | 可以重复 |
| 一般不能为空 | 可以为空 |
| 一个表通常一个主键 | 一个表可以有多个外键 |
3. 外键可以引用普通字段吗?
参考答案
一般不能。外键引用的字段必须是主键或唯一键。例如 REFERENCES class(id),这里的 id 通常是主键。
4. 创建外键时需要满足什么条件?
参考答案
- 两个字段类型一致、长度一致。
- 字符集最好一致。
- 被引用字段必须是主键或唯一键。
- 存储引擎必须支持外键(如 InnoDB)。
5. 为什么删除父表数据会失败?
参考答案
因为子表存在引用。例如 student.class_id = 1,这时执行 DELETE FROM class WHERE id = 1;,数据库会阻止删除——父表记录正在被子表引用。
6. 什么是级联删除?
参考答案
删除父表数据时,自动删除对应子表数据。例如 ON DELETE CASCADE,删除班级时,该班级下所有学生也会被删除。
7. 什么是级联更新?
参考答案
当父表主键变化时,子表外键自动同步修改。例如 ON UPDATE CASCADE。
8. 为什么互联网公司很多不用外键?
参考答案
主要原因:性能损耗、分库分表困难、微服务不方便、影响高并发。所以很多公司不在数据库层加外键,而是在代码层维护关系。
9. 外键一定会提高数据库安全性吗?
参考答案
会提高数据一致性,但未必提高系统性能——有时反而降低写入效率,因为插入、删除时需要检查约束。
10. 外键和索引有什么关系?
参考答案
外键用于维护关系,索引用于提高查询速度。两者作用不同,但外键字段通常会建立索引以加速关联查询。
11. 一对多关系怎么设计?
参考答案
例如一个班级多个学生。班级表:主键 id;学生表:class_id 作为外键。即“多”的一方存外键。
12. 多对多关系怎么设计?
参考答案
需要第三张中间表。例如学生选课:一个学生选多门课,一门课有多个学生。设计中间表 student_course,包含 student_id 和 course_id 两个外键。
13. 下面 SQL 为什么报错?
CREATE TABLE student(
id INT PRIMARY KEY,
class_id INT,
FOREIGN KEY(class_id)
REFERENCES class(id)
);
参考答案
可能原因:class 表不存在、class.id 不是主键/唯一键、存储引擎不支持、类型不一致。
14. 什么情况下适合使用外键?
参考答案
适合:小型项目、教学项目、管理系统、数据一致性要求高的场景。不太适合:超高并发的互联网系统。
15. truncate 和 delete 对外键有什么影响?
参考答案
DELETE是逐行删除,会触发外键检查。TRUNCATE是直接清空表,有外键时通常不能直接使用。
