很多开发同学对 MySQL 外键(Foreign Key)一直处于似懂非懂的状态:
知道外键是用来关联两张表,但不敢用、不会用、不知道线上能不能开、不知道为什么大厂基本禁用外键。
这篇博客用最通俗、实战化的方式,从零入门 MySQL 外键,不讲废话、只讲开发能用的干货。
一、外键到底是干嘛的?一句话听懂
外键 = 数据库层面的自动数据关联校验
两张表:
- 主表(父表):被关联的表,比如用户表、分类表
- 从表(子表):关联别人的表,比如订单表、文章表
外键作用:保证子表的数据,一定在主表存在,杜绝脏数据
举个例子:
订单表有个 user_id
如果不加外键,你可以随便插入一条 user_id=99999(用户根本不存在),产生脏数据。
如果加了外键:数据库直接拦截,插不进去、改不了、删不掉。
二、外键核心三要素(入门必记)
-
引擎必须是 InnoDB
MyISAM 不支持外键,写了也不生效。
-
字段类型必须严格一致
主表主键 int,子表外键也必须 int;
长度、符号、是否 unsigned 必须一致,否则创建失败。
-
必须建立索引
外键字段会自动创建索引,不用手动建。
三、手把手入门:最简单的外键示例
先建主表(用户表)
sql
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30)
) ENGINE=InnoDB;
再建从表(订单表),绑定外键
sql
CREATE TABLE `order` (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
price DECIMAL(10,2),
-- 外键关联 user.id
FOREIGN KEY (user_id) REFERENCES user(id)
) ENGINE=InnoDB;
生效效果
- ❌ 不能插入不存在的 user_id
sql
INSERT INTO `order`(user_id,price) VALUES(999,99.9);
-- 报错:外键约束失败
- ✅ 只能插入真实存在的用户ID
这就是外键最核心的价值:数据一致性约束
四、外键四大联动规则(入门重中之重)
建外键时,ON DELETE 和 ON UPDATE 是新手最懵的地方,四种规则一次性讲透:
1. CASCADE 级联更新/删除
父表改,子表跟着改;父表删,子表自动删
适合:订单、子明细数据
风险:误删主数据,子表大批量数据被清空,线上高危
2. RESTRICT(默认)/ NO ACTION
父表有关联子数据,禁止删除/修改
最安全、最常用!
例子:用户有订单,不让删用户,防止数据错乱
3. SET NULL
删除主表数据,子表外键自动置为NULL
前提:外键字段允许为 NULL
适合:关联关系可空的业务,比如可选分类、可选上级
4. SET DEFAULT
恢复默认值,基本不用、极少场景
开发最推荐组合
sql
FOREIGN KEY (user_id) REFERENCES user(id)
ON UPDATE CASCADE
ON DELETE RESTRICT
更新用户ID同步更新,有订单不让删用户,最符合业务逻辑。
五、外键的真实好处(为什么学它)
-
杜绝脏数据
应用层BUG、人为乱改SQL、导入数据,都无法产生无效关联数据
-
保证数据一致性
多服务、多代码入口操作同一张表时,代码层约束会失效,数据库约束最稳
-
简化业务代码
不用每次新增订单都手动判断用户是否存在,数据库自动兜底
六、重点:为什么国内大厂基本不用外键?
新手最大疑惑:
外键这么好用,为什么阿里、字节规范 禁止使用外键?
我给你讲最真实的原因,不是玄学:
1. 外键会锁表、锁行,高并发性能极差
外键校验需要关联查表,高并发插入、更新会引发锁等待、死锁,压垮数据库。
2. 问题排查极难
线上报错 foreign key constraint fails,不看表结构根本不知道哪里冲突,排查成本极高。
3. 分布式、分库分表完全不支持
外键只能单库生效,一旦分库分表、微服务拆分,外键直接作废。
4. 业务灵活性差
业务迭代经常需要数据迁移、批量订正、临时删数据,外键会卡死所有操作。
5. 代码层约束完全可以替代
现在项目统一规范:逻辑约束放代码,数据约束不放数据库
七、到底什么时候用?什么时候不用?
✅ 适合用外键的场景(小项目、内部系统)
- 单体项目、低并发后台管理系统
- 数据质量要求高、不允许脏数据
- 不会分库分表、长期单库运行
- 内部报表、后台系统、OA、CRM
❌ 绝对不建议用外键的场景(线上互联网项目)
- 高并发业务:订单、支付、用户
- 微服务、分布式项目
- 未来会分库分表的业务
- 需要频繁批量更新、迁移数据的表
八、新手最容易踩的5个外键坑
- 字段类型不一致(最常见报错)int / unsigned 不匹配直接建表失败
- MyISAM引擎建外键,不报错但完全不生效
- 开启外键后批量删数据报错,忘了子表存在
- 线上误开CASCADE,删一条主数据,连带删除几万条子数据
- 导入数据顺序错误,先插子表数据,主键不存在报错
九、企业替代方案(不用外键如何保证一致性?)
大厂不用外键,但绝对不是不管数据一致性,而是换方案:
- 业务层代码判断:新增前校验主数据是否存在
- 逻辑删除代替物理删除:所有数据只更新delete_flag,不真实删除
- 定时任务清洗脏数据:定时巡检无效关联数据
- 唯一索引、普通索引兜底
结尾
外键本身不是垃圾技术 ,它是非常优秀的单库数据一致性方案。
它的问题不在于功能,而在于不适应高并发、分布式、快速迭代的互联网业务。
新手入门记住一句话:
小系统大胆用外键保数据质量,线上高并发、分布式项目坚决不用外键,代码层兜底一致性。