最近,小编发现Reddit上有一篇名为《臭名昭著的、存在了20年的MySQL Bug#11472已被修复》的帖子火了。这个从2005年就被提交、伴随MySQL二十年的经典Bug,终于在2026年被修复。
一、 Bug #11472 到底是什么问题?
以下是该Bug的提报者Omer Barnir在2005年提交Bug时的原始描述:
[2005年6月21日 0:08] Omer Barnir
描述:
当由于表中存在外键定义而间接更新/删除表中的行时,该表上的触发器将不会按要求执行,如下所示:
omer@linux:~/source/src50_0620/client> ./mysql --socket=/home/omer/source/src50_0620/mysql-test/var/tmp/master.sock --user=root
欢迎使用 MySQL 监视器。命令以 ; 或 \g 结尾。
你的 MySQL 连接 ID 为 1,服务器版本为:5.0.8-beta-log。
输入 ‘help;’ 或 ‘\h’ 获取帮助。输入 ‘\c’ 清除缓冲区。
mysql> USE test;数据库已更改mysql>mysql> DROP TABLE IF EXISTS t1,t2;查询成功,影响 0 行,2 个警告 (0.00 秒)mysql>mysql> CREATE TABLE t1 (id INT NOT NULL, col1 char(50), PRIMARY KEY (id)) ENGINE=INNODB;查询成功,影响 0 行 (0.01 秒)mysql> CREATE TABLE t2 (id INT PRIMARY KEY, f_id INT, INDEX par_ind (f_id), col1 char(50),-> FOREIGN KEY (f_id) REFERENCES t1(id) ON DELETE SET NULL) ENGINE=INNODB;查询成功,影响 0 行 (0.01 秒)mysql>mysql> create trigger tr_t2 after update on t2-> for each row set @counter=@counter+1;查询成功,影响 0 行 (0.00 秒)mysql>mysql> insert into t1 values (1,'Department A');查询成功,影响 1 行 (0.00 秒)mysql> insert into t1 values (2,'Department B');查询成功,影响 1 行 (0.00 秒)mysql> insert into t1 values (3,'Department C');查询成功,影响 1 行 (0.00 秒)mysql> insert into t2 values (1,2,'Emp 1');查询成功,影响 1 行 (0.00 秒)mysql> insert into t2 values (2,2,'Emp 2');查询成功,影响 1 行 (0.00 秒)mysql> insert into t2 values (3,2,'Emp 3');查询成功,影响 1 行 (0.00 秒)mysql> insert into t2 values (4,2,'Emp 4');查询成功,影响 1 行 (0.00 秒)mysql> insert into t2 values (5,2,'Emp 5');查询成功,影响 1 行 (0.00 秒)mysql> set @counter=0;查询成功,影响 0 行 (0.00 秒)mysql> select * from t1;+----+--------------+| id | col1 |+----+--------------+| 1 | Department A || 2 | Department B || 3 | Department C |+----+--------------+3 rows in set (0.00 秒)mysql> select * from t2;+----+------+-------+| id | f_id | col1 |+----+------+-------+| 1 | 2 | Emp 1 || 2 | 2 | Emp 2 || 3 | 2 | Emp 3 || 4 | 2 | Emp 4 || 5 | 2 | Emp 5 |+----+------+-------+5 行结果 (0.00 秒)mysql> select @counter;+----------+| @counter |+----------+| 0 |+----------+1 行结果 (0.00 秒)mysql> delete from t1 where id=2;查询成功,影响 1 行 (0.05 秒)mysql>mysql> select * from t1;+----+--------------+| id | col1 |+----+--------------+| 1 | Department A || 3 | Department C |+----+--------------+2 行结果 (0.00 秒)mysql> select * from t2;+----+------+-------+ | id | f_id | col1 |+----+------+-------+| 1 | NULL | Emp 1 || 2 | NULL | Emp 2 || 3 | NULL | Emp 3 || 4 | NULL | Emp 4 || 5 | NULL | Emp 5 |+----+------+-------+5 rows in set (0.00 sec)mysql> select @counter;+----------+| @counter |+----------+| 0 |+----------+1 行记录 (0.00 秒)***** 注意:此时表 t2 中更新了 5 行,@count 的值预期为 '5'(每次触发触发器都会将其值加 1),但该值仍然为零,表明触发器未执行。以下语句显示,当直接更新表 't2'时,触发器本身会被执行:mysql> update t2 set col1='Emp 5a' where id=5;查询成功,影响 1 行 (0.00 秒)匹配行数:1 更改行数:1 警告数:0mysql> select * from t2;+----+------+--------+| id | f_id | col1 |+----+------+--------+| 1 | NULL | Emp 1| | 2 | NULL | Emp 2 || 3 | NULL | Emp 3 || 4 | NULL | Emp 4 || 5 | NULL | Emp 5a |+----+------+--------+5 行结果 (0.00 秒)mysql> select @counter;+----------+| @counter |+----------+| 1 |+----------+1 行结果 (0.00 秒)*****在这种情况下,触发器已执行(@count 设置为 '1')mysql>mysql> drop table t2,t1;查询成功,0 行受影响 (0.00 秒)mysql> quitByeomer@linux:~/source/src50_0620/client>
如何重现:
在 mysql 客户端中运行以下命令:
USE test;DROP TABLE IF EXISTS t1,t2;CREATE TABLE t1 (id INT NOT NULL, col1 char(50), PRIMARY KEY (id)) ENGINE=INNODB;CREATE TABLE t2 (id INT PRIMARY KEY, f_id INT, INDEX par_ind (f_id), col1 char(50),FOREIGN KEY (f_id) REFERENCES t1(id) ON DELETE SET NULL) ENGINE=INNODB;CREATE Trigger tr_t2 After Update on t2For Each Row Set @counter=@counter+1;INSERT INTO t1 VALUES (1,'Department A');INSERT INTO t1 VALUES (2,'Department B');INSERT INTO t1 VALUES (3,'Department C');INSERT INTO t2 VALUES (1,2,'Emp 1');INSERT INTO t2 VALUES (2,2,'Emp 2');INSERT INTO t2 VALUES (3,2,'Emp 3');INSERT INTO t2 VALUES (4,2,'Emp 4');INSERT INTO t2 VALUES (5,2,'Emp 5');SET @counter=0;SELECT * FROM t1;SELECT * FROM t2;SELECT @counter;DELETE FROM t1 WHERE id=2;SELECT * FROM t1;SELECT * FROM t2;SELECT @counter;UPDATE t2 SET col1='Emp 5a' WHERE id=5;SELECT * FROM t2;SELECT @counter;DROP TABLE t2,t1;
建议的修复方案:
在上述场景中执行触发器。
二、为什么这个Bug能存在二十年?
其实在Omer Barnir提交Bug的当天,MySQL InnoDB存储引擎的创始人Heikki Tuuri就亲自回复:
第二天,他又补充表示,会在MySQL 5.1版本修复该问题,并将该Bug的严重级别降低至P3。
然而事情并未如期推进:
2007年,Heikki Tuuri 改口称MySQL自身的外键实现最终会解决这个问题,但仍然需要一些时间。
2009年,MySQL核心贡献者Konstantin Osipov正式确认 5.1 版本不会修复这个Bug。
2013年,MySQL核心开发团队的资深工程师Ståle Deraas进一步解释,解决这个问题需要大量的开发工作,并非简单的漏洞修复。
面对年复一年的拖延,开发者的不满与质疑也越来越强烈:
很多人不解,一个早已被官方确认的功能问题,为什么会被搁置如此之久?
2020年,分布式数据库TiDB幕后公司PingCAP的技术支持工程师Daniël van Eeden的留言或许能解释这个问题:
要解决这个问题,可行的方式是新增一个系统配置项,允许在现有行为和新修复行为之间切换。
另一种“方案”是为触发器增加一个标记位来控制这一行为,但这很可能不符合ISO SQL标准,而且还需要用户修改所有已存在的触发器。
即便限制基于语句的复制,也只能缓解部分问题,无法彻底根治。
三、一个Bug二十年的社区狂欢
在等待这个Bug修复的过程当中,评论区比Bug本身还精彩:
有给这个Bug庆祝生日的:
各种脑洞调侃更是层出不穷:
还有网友好奇起了当年的Bug提交者:
Omer Barnir亲自现身回复:
更离奇的是,还有人写了一封“求婚情书”:
二十年来,你始终屹立不倒——未解决,未触及,如同坚韧的丰碑,历经无数次更新。当其他问题来来去去时,你却始终如一,提醒着我,即便在充斥着外键和层层变化的时代,有些事情也永远不会如预期般发生。
从遇见你的那一刻起,我就知道你很特别,你是个未解之谜,一个值得拥抱的挑战。许多人试图修复你,但或许你注定无法被修复。或许,你注定要被爱。
所以,我单膝跪地:
我的亲爱的#11472,你愿意嫁给我吗?你愿意成为我永远未解决的问题吗?你愿意以某种方式闯入我的生活吗?即使它并非如潮水般涌来,而是以某种限制的方式?你愿意与我共创未来吗?就像外键更新一样,没有任何事物能够让你离开?
答应我,我将永不放手。答应我,我们将永远并肩而立——永远未解,永远相连。
永远属于你,
最忠诚的 MySQL 用户,绝不放手。
四、活了二十年的Bug,终于退场
整整二十年,它从一个功能缺陷,变成了程序员圈子“臭名昭著”的传奇老Bug。
在Reddit帖子的下方,有网友一语道尽这个Bug的地位:
今年,它终于迎来大结局:2026年3月,官方通过 WL#17024 修复了这个Bug。至此,这个跨越二十年、收获无数吐槽与玩梗的传奇Bug,终于画上句号。
有趣的是,盼了二十年的修复真的到来时,有网友却表示:
“搞什么鬼?我一直很依赖这个功能!请改回来。”
“什么?!那我们以后每年该给谁买蛋糕呢……”
版权申明:内容来源网络,版权归原创者所有,如有侵权请联系删除
想了解更多干货,可通过下方扫码关注

可扫码添加上智启元官方客服微信👇

17认证网








