定义:外键(Foreign Key)是MySQL InnoDB引擎提供的参照完整性约束。外键字段引用另外一张表的主键或者唯一索引字段,用来保证关联数据合法。
主表(父表):被引用的表,主键作为关联基准。
从表(子表):包含外键字段的表,外键引用主表主键。
约束效果:从表外键的值,只能是主表主键已存在的值,或者NULL。
存储引擎必须是 InnoDB,MyISAM引擎不支持外键约束。
外键字段和引用主表主键数据类型、字符集、排序规则必须完全一致。
主表被引用字段必须建立主键索引或者唯一索引。
外键字段建议单独建立索引,提升联表查询性能。
当父表记录删除或者更新时,通过ON DELETE、ON UPDATE控制子表外键行为:
| 约束行为 | 说明 |
|---|---|
| RESTRICT | 默认行为。如果子表存在关联数据,禁止删除/更新主表记录,直接抛出报错。 |
| CASCADE | 级联操作,主表删除/更新,子表关联数据同步删除或更新。 |
| SET NULL | 主表删除/更新,子表外键字段设置为NULL,前提是外键字段允许NULL。 |
| NO ACTION | 和RESTRICT基本一致,不做任何操作,抛出约束报错。 |
业务场景:用户表 user 为主表,订单表 order 为子表。订单归属某个用户,通过user_id外键关联user表主键id。
创建主表 user(用户表)
CREATE TABLE `user` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户主键ID', `username` VARCHAR(50) NOT NULL COMMENT '用户名', `phone` VARCHAR(11) NOT NULL COMMENT '手机号', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户主表';
创建从表 order(订单表,定义外键)
CREATE TABLE `order` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单主键', `order_no` VARCHAR(32) NOT NULL COMMENT '订单编号', `user_id` INT UNSIGNED NOT NULL COMMENT '关联用户ID,外键', `amount` DECIMAL(10,2) NOT NULL COMMENT '订单金额', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `fk_order_user` (`user_id`), CONSTRAINT `fk_order_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单子表';
外键说明:
CONSTRAINT fk_order_user:外键名称,方便后续删除外键。
REFERENCES user(id):子表user_id引用主表user的id。
ON DELETE RESTRICT:用户存在订单时,不能删除用户。
ON UPDATE CASCADE:主表用户id更新,订单user_id同步更新。
插入测试数据
-- 主表插入用户
INSERT INTO `user`(username,phone) VALUES ('zhangsan','13800138000');
-- 子表插入订单(user_id=1在user表存在,可以成功)
INSERT INTO `order`(order_no,user_id,amount) VALUES ('ORD20260901001',1,99.00);
-- 插入user_id=999(用户不存在),外键直接报错,禁止插入
INSERT INTO `order`(order_no,user_id,amount) VALUES ('ORD20260901002',999,199.00);删除主表数据(RESTRICT效果)
-- user表id=1存在订单,执行删除会报错,无法删除 DELETE FROM `user` WHERE id=1;
修改主表主键(CASCADE效果)
-- 更新主表id,子表user_id自动同步更新 UPDATE `user` SET id=10 WHERE id=1; -- 查询订单表,user_id已经变成10 SELECT * FROM `order`;
给已有表新增外键
ALTER TABLE `order` ADD CONSTRAINT `fk_order_user` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
删除外键
ALTER TABLE `order` DROP FOREIGN KEY `fk_order_user`;
查看表外键信息
-- 查看建表语句,可以看到外键定义 SHOW CREATE TABLE `order`; -- 查询外键约束详情 SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'user';
业务场景:删除用户时,保留订单记录,订单user_id置空。注意:user_id字段必须允许NULL。
ALTER TABLE `order` MODIFY COLUMN `user_id` INT UNSIGNED NULL; ALTER TABLE `order` ADD CONSTRAINT `fk_order_user` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
执行删除用户SQL后,订单表user_id自动变为NULL,订单数据保留。
数据库层面强制数据参照完整性,杜绝无效关联脏数据。
级联操作简化业务代码,不需要手写大量关联删除逻辑。
增加写入、更新性能开销,每次修改都会校验约束。
大表、高并发场景下容易产生锁等待,降低并发能力。
分库分表架构无法使用数据库外键。
中小型项目、内部管理系统,可以使用外键,减少脏数据。
高并发互联网核心业务、分库分表项目,推荐业务层代码维护数据一致性,不使用数据库外键。
开发测试环境可以开启外键校验,生产高并发场景谨慎使用。
字段类型不一致直接创建外键失败(INT 和 BIGINT 不能互相引用)。
字符集、排序规则不一致,报外键创建失败。
表中已有脏数据,会阻止外键创建,需要先清理脏数据。
外键没有单独建索引,大表关联查询性能极差。
MySQL外键是InnoDB提供的参照完整性约束,核心作用是保证主从表之间引用合法。四种级联模式(RESTRICT/CASCADE/SET NULL/NO ACTION)适配不同业务场景。但高并发互联网项目一般不推荐在数据库层使用外键,优先在业务代码控制数据关联。
以上就是小编给玩家们带来的教程内容,更多教程请关注趣游软件园。