MySQL外键约束详解

MySQL外键约束详解 一、外键约束的概念1. 定义与作用外键约束FOREIGN KEY用于实现参照完整性Referential Integrity确保子表中外键列的值要么为NULL要么在父表的主键/唯一键列中存在。它强制表与表之间的引用关系防止出现“孤儿记录”子表中引用了父表中不存在的值。2. 相关概念术语说明主键PK唯一标识表中一行记录的列或列组合且不允许为NULL。外键FK子表中与父表主键/唯一键对应的列允许为NULL除非额外设置NOT NULL。父表主表被外键引用的表通常是主键所在表。子表从表包含外键的表受外键约束限制。参照完整性子表外键值必须等于父表主键值或为NULL。级联操作通过ON DELETE/ON UPDATE指定父表数据变动时子表的自动处理方式。3. 核心要点数据类型必须完全一致外键列与被引用列的数据类型、长度、符号SIGNED/UNSIGNED必须完全相同否则无法创建外键。外键允许NULL除非外键列显式定义为NOT NULL否则可以存储NULL表示“未引用任何父表记录”。被引用列必须有索引父表被引用的列必须是主键或唯一键已自动有索引否则 MySQL 会报错。自动创建索引在 InnoDB 中创建外键时若外键列无索引会自动创建一个与外键同名的索引便于检查约束。存储引擎要求仅InnoDB支持外键约束MyISAM 等引擎不支持。级联操作重要可通过ON DELETE/ON UPDATE设置级联行为避免因父表数据变更导致子表数据孤立。二、创建外键约束1. 语法一在已有表上添加外键-- 写法 A为约束命名推荐 ALTER TABLE 子表名 ADD CONSTRAINT 外键约束名 FOREIGN KEY (外键列名) -- 注意列名必须用括号括起 REFERENCES 父表名(被引用列名) [ON DELETE 参照动作] [ON UPDATE 参照动作]; -- 写法 B不命名系统自动生成名称不推荐 ALTER TABLE 子表名 ADD FOREIGN KEY (外键列名) REFERENCES 父表名(被引用列名) [ON DELETE 参照动作] [ON UPDATE 参照动作];2. 语法二创建表时定义外键CREATE TABLE 子表名 ( 列名1 数据类型 [约束], ... 列名n 数据类型 [约束], CONSTRAINT 外键约束名 FOREIGN KEY (外键列名) REFERENCES 父表名(被引用列名) [ON DELETE 参照动作] [ON UPDATE 参照动作] );3. 参照动作选项含义CASCADE父表删除/更新行时子表对应行自动删除/更新。SET NULL父表删除/更新行时子表外键列设为NULL要求外键列允许NULL。NO ACTION与RESTRICT类似拒绝父表的删除/更新操作默认行为。RESTRICT拒绝父表的删除/更新操作默认行为。默认行为若省略ON DELETE/ON UPDATE则默认为RESTRICT即父表有子表引用时禁止删除/更新。三、查看外键约束名1. 通过information_schema查看SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME子表名 AND COLUMN_NAME外键字段名;2. 通过SHOW CREATE TABLE查看constraint 后是外键名show create table 表名;四、删除外键约束1. 删除外键ALTER TABLE 子表名 DROP FOREIGN KEY 外键名;2. 删除自动创建的索引MYSQL在建外键后,会自动建一个与外键字段同名的索引-- 先查看索引 SHOW INDEX FROM 子表名; -- 如果不再需要该索引则删除 ALTER TABLE 子表名 DROP INDEX 索引名;注意删除外键后MySQL 不会自动删除为外键创建的索引需手动删除。五、外键的优点与注意事项1. 优点保证数据完整性杜绝无效引用确保关联数据一致。自动化级联操作通过ON DELETE CASCADE等选项自动维护关联数据。减少应用层校验负担数据库层面强制约束无需在业务代码中重复检查。2. 注意事项性能影响每次插入/更新/删除都需要检查外键约束可能影响性能高并发场景。锁争用外键检查可能增加锁的持有时间可能导致死锁或并发下降。存储引擎限制仅 InnoDB 支持外键MyISAM 等不支持。循环引用避免多个表之间形成循环外键依赖否则可能导致无法插入或删除数据。数据导入/迁移临时禁用外键检查可提升导入速度但需确保数据完整性级联操作风险CASCADE可能意外删除/更新大量数据需谨慎使用。六、完整操作实例以下示例在 MySQL 中运行演示外键的创建、约束效果、级联操作、查看与删除。1. 创建数据库与表-- 创建数据库并使用 CREATE DATABASE IF NOT EXISTS fk_demo; USE fk_demo; -- 父表部门表 CREATE TABLE dept ( dept_id INT AUTO_INCREMENT PRIMARY KEY, dept_name VARCHAR(50) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 子表员工表创建时定义外键并设置级联删除 CREATE TABLE emp ( emp_id INT AUTO_INCREMENT PRIMARY KEY, emp_name VARCHAR(50) NOT NULL, dept_id INT, CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES dept(dept_id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;2. 插入测试数据-- 向父表插入部门 INSERT INTO dept (dept_name) VALUES (研发部), (市场部), (人事部); -- 向子表插入员工dept_id 必须在 dept 表中存在或为 NULL INSERT INTO emp (emp_name, dept_id) VALUES (张三, 1), (李四, 2), (王五, 1), (赵六, NULL);3. 测试外键约束插入无效值会报错-- 尝试插入一个不存在的 dept_id会报错 INSERT INTO emp (emp_name, dept_id) VALUES (钱七, 99);预期错误Cannot add or update a child row: a foreign key constraint fails4. 测试级联删除与更新-- 查看当前员工数据 SELECT * FROM emp; -- 删除父表 dept_id1 的部门研发部子表关联员工会自动删除 DELETE FROM dept WHERE dept_id 1; -- 再次查看员工表张三和王五会被自动删除 SELECT * FROM emp; -- 更新父表 dept_id2 为 20子表关联的 dept_id 也会自动更新 UPDATE dept SET dept_id 20 WHERE dept_id 2; -- 查看员工表李四的 dept_id 变为 20 SELECT * FROM emp;5. 查看外键约束名与定义-- 方法1通过 information_schema 查看 SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAMEemp AND COLUMN_NAMEdept_id; -- 方法2通过 SHOW CREATE TABLE 查看 SHOW CREATE TABLE emp;6. 删除外键约束及索引-- 删除外键 ALTER TABLE emp DROP FOREIGN KEY fk_emp_dept; -- 查看索引确认是否还有自动创建的索引 SHOW INDEX FROM emp; -- 如果需要删除索引索引名通常与外键名相同 ALTER TABLE emp DROP INDEX fk_emp_dept;七、常见问题与技巧外键列是否允许NULL允许。除非外键列定义为NOT NULL否则可以存储NULL表示“未关联”。如何临时禁用外键检查SET FOREIGN_KEY_CHECKS 0; -- 禁用 -- 导入数据或修改操作 SET FOREIGN_KEY_CHECKS 1; -- 启用为什么创建外键时提示 “ERROR 1215 (HY000): Cannot add foreign key constraint”常见原因外键列与被引用列的字符集/排序规则不一致。存储引擎不是 InnoDB。被引用列没有索引不是主键或唯一键。数据类型不一致包括UNSIGNED属性。外键约束与索引的关系InnoDB 要求外键列必须有索引如果没有会自动创建。删除外键后索引不会自动删除需手动清理。级联操作的风险ON DELETE CASCADE会级联删除子表数据可能导致意外数据丢失建议在关键业务中谨慎使用或通过业务逻辑处理。