

























某天晚上,群里突然有人@我,说开发环境出现报错,一查发现是我负责的接口出了问题,瞬间虎躯一震,赶紧定位问题。

谜底就在谜面上:主表数据被删除,但子表仍保留外键约束,导致删除操作直接失败。
三分钟解决问题,行云流水,毫不拖泥带水。
但这件事引发了我的反思:这种错误太低级了,低级到刚毕业的我都不可能犯,但工作多年后的我反而踩坑了。
复盘原因,主要有三点:
对外键本质理解不够深入
人云亦云、浅尝辄止,没有真正吃透原理。
温故而知新,希望未来不再被同样的问题“回旋镖”命中。
过度依赖 DBA 兜底,思考偷懒
经验主义害人,任何技术点都不能“不带脑子”。
对业务上游逻辑不够熟悉
不知道上游业务会执行删除操作。
后续需要加强业务文档沉淀、多总结、多梳理。
数据库外键,是一个熟悉又陌生的词。
至于为什么不建外键?别问,问就是互联网公司传统!
当然,主要是没权限。
那为什么现在又开始建了?
一代版本一代神,换工作了 😂
外键(Foreign Key) 是一种数据约束,用于强制维护两张表之间的关联关系。
核心作用:保证数据不乱、不丢、不错。
没有外键,很容易出现三类脏数据:
有了外键:
CREATE TABLE 子表 (
字段名 数据类型,
-- 外键定义
CONSTRAINT 外键名称
FOREIGN KEY (子表字段)
REFERENCES 主表(主表字段)
-- 可选:级联规则
ON DELETE 行为
ON UPDATE 行为
);
ALTER TABLE 子表
ADD CONSTRAINT 外键名称
FOREIGN KEY (子表字段)
REFERENCES 主表(主表字段)
ON DELETE 行为
ON UPDATE 行为;
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
其他数据库如 SQL Server:
ALTER TABLE 表
ALTER CONSTRAINT 外键名
ON DELETE CASCADE;
外键的灵魂就是:删除/更新主表时,子表应该如何自动处理。

ON DELETE RESTRICT -- 不允许删除
ON UPDATE CASCADE -- 允许改 ID,自动同步
降低写入性能
插入/删除都需要额外校验,高并发场景下影响明显。
隐式加锁,易导致锁等待、死锁
例如插入子表时,数据库会自动查询并锁定主表对应记录,提高死锁概率。
不支持分库分表
外键是数据库引擎内部功能,只能在同一个库、同一个实例内生效。
分布式架构下完全无法使用。
级联删除风险极高
误操作难以恢复,不符合互联网业务“可容错、可兜底”的需求。
互联网企业不是不会用外键,而是不敢用、不能用、不需要用。
业务更需要:逻辑删除、数据迁移、临时异常容忍、灵活清洁数据。
如果你还是听不懂,那说人话就是,我们言必谈高并发,分布式,高可用,只有你坚持古法单数据库,强一致性,活该你背锅。

是的,外键名称不能重复。
只要现有数据完全合法(都能在主表找到对应记录),就可以添加;否则会直接失败。
不需要主键,但必须具备唯一性。
唯一键(UNIQUE)也可以被外键引用。
举个例子,当你执行这条SQL时,因为外键约束的存在,会偷偷帮你做这两件事情,
INSERT INTO 子表 (ProposalId) VALUES (100)
1. 主动去查一下主表,看看id=100存在吗? -- 隐式加锁
2. 锁定主表的那条记录,防止在你插入的过程中,主表数据被删掉 -- 加S锁
因为锁的存在,极大的提高了等待,死锁的可能性。
外键能生效,是因为数据库引擎能直接在内部执行检查,加锁,校验等功能,它只能管好自己。
而互联网的架构往往是分布式,身份证表可能被分为N个表,N个库。它们甚至不在同一个库,同一个机器上。
那么问题来了,身份证表在数据库A,学生表在数据库B,如何建立外键关系? 别忘了,数据库只能管好自己。更何况跨服务器的情况,那更加鞭长莫及了。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。