必须用InnoDB引擎且父子表字段类型、符号、长度完全一致,否则报ERROR 1005或errno: 150;建表时直接定义外键最稳妥,被引用列须为主键或唯一键,ON DELETE行为需按业务选择,已有表加外键前须清理孤立值并确保约束名唯一。

MySQL中创建外键约束,必须用 InnoDB 引擎,且父子表字段类型、符号、长度要完全一致——不满足任一条件都会报错,比如 ERROR 1005 (HY000): Can't create table 或更隐晦的 errno: 150。
创建表时直接定义外键(推荐)
这是最稳妥的方式,避免后续数据冲突。关键点在于:外键列要显式声明类型(包括 UNSIGNED),被引用列必须是主键或唯一键,且两者引擎均为 InnoDB。
示例:
CREATE TABLE users ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT ) ENGINE=InnoDB; <p>CREATE TABLE orders ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, user_id INT UNSIGNED NOT NULL, CONSTRAINT fk_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB;
-
user_id和users.id都是INT UNSIGNED,否则会失败 -
ON DELETE CASCADE表示删用户时自动删其订单;若想禁止删除,改用ON DELETE RESTRICT - 没加
ENGINE=InnoDB的话,语句看似成功,但外键实际无效(MyISAM 忽略外键语法)
给已有表添加外键(需先清理数据)
用 ALTER TABLE 加外键前,必须确保子表里所有 user_id 值在父表 users.id 中都存在,且没有重复约束名。
常见错误现象:
- 执行
ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(id)报errno: 150→ 检查user_id是否有值不在users.id中 - 报
ERROR 1022 (HY000): Can't write; duplicate key in table→ 约束名重复,或该列已有同名索引 - 父表
users.id缺少索引(非主键/唯一键)→ 先加ALTER TABLE users ADD UNIQUE (id)或设为主键
外键列是否允许 NULL?
默认允许 NULL,除非你显式加了 NOT NULL。这点常被忽略,导致误以为“外键必须填值”。
- 子表中
user_id为NULL是合法的,表示该订单暂未归属用户 - 如果业务上不允许空关联,必须加
NOT NULL,否则约束形同虚设 -
ON DELETE SET NULL要求外键列本身允许NULL,否则会失败
为什么 SHOW CREATE TABLE 看不到外键定义?
不是没生效,而是 MySQL 的 SHOW CREATE TABLE 默认不显示外键细节(尤其在旧版本)。真正验证方式是:
- 查
information_schema.KEY_COLUMN_USAGE:SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'orders' AND CONSTRAINT_SCHEMA = 'your_db'; - 执行非法插入:
INSERT INTO orders (user_id) VALUES (999999);→ 应报Cannot add or update a child row - 注意:某些客户端(如 phpMyAdmin)可能缓存表结构,改完后需刷新或重连
外键不是开关按钮,它是嵌入在存储引擎里的行为规则;一旦建错,修复成本远高于建对——尤其在线上表数据量大时,ALTER TABLE 可能锁表数分钟。


















