引起外键约束的并行截断会在插入(mySQL 8.x)上失败吗?
我缺少某些内容,还是在MySQL 8中进行的错误,尝试了最新版本8.0.29和其他版本。这曾经在5.7中无问题。幸运的是,我能够在bash中复制它,但是我们在测试设置中遇到了它。似乎您可以获得一个状态,即表具有正确的ID记录的状态,以适用于外键约束,但MySQL仍然会引发错误。
基本设置:
- 创建表A
- 表的ID上具有外键约束。
- 创建表B
- 这在
- , 并非总是如此,但是如果您运行100次,它将因外键约束错误而失败。
这是复制它的代码。这将使mySQL处于不良状态,您甚至可以连接到数据库并尝试插入,并且会失败。
#!/bin/bash
DB_USER='root';
DB_PASSWD='root';
DB_NAME='mysql_8_bug';
TABLE_A='a';
TABLE_B='b';
set -m
#setup
mysql --user=$DB_USER --password=$DB_PASSWD << EOF
CREATE DATABASE IF NOT EXISTS $DB_NAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
DROP TABLE IF EXISTS $TABLE_A, $TABLE_B;
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
CREATE TABLE $TABLE_A (id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
CREATE TABLE $TABLE_B
(id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
int_a_id BIGINT(20) UNSIGNED DEFAULT NULL,
CONSTRAINT fk_a_id FOREIGN KEY (int_a_id) REFERENCES a (id));
EOF
#end of setup
for i in {0..100}
do
#run truncate in parallel
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="SET @@session.FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE $TABLE_A; SET @@session.FOREIGN_KEY_CHECKS = 1;" &
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="SET @@session.FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE $TABLE_B; SET @@session.FOREIGN_KEY_CHECKS = 1;" &
wait
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="INSERT INTO $TABLE_A (id) VALUES (1);"
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="INSERT INTO $TABLE_B (int_a_id) VALUES (1);"
if [ $? -gt 0 ]
then
echo "It Happened!!! You can now check the database you will see that table a has value of id 1. The database will be in a bad state, running INSERT in table b will not work."
exit 0
fi
done
Is there something I'm missing or does this seems like a bug with MySQL 8, tried the latest version 8.0.29 and other versions in between. This used to work in 5.7 without issues. Luckily, I was able to reproduce this in bash but we encountered it within our testing setup. It seems like you can get a state where a table has record with the correct id for the foreign key constraint but MySQL still throws an error.
Basic setup:
- Create table A
- Create table B, this has a foreign key constraint on id of table A
- parallel TRUNCATE table A and table B (disable the session FOREIGN_KEY_CHECKS)
- insert into table A
- insert into table B <-- this will fail, not always but if you run it 100 times it will fail with foreign key constraint error.
Here is the code to reproduce it. This will put MySQL into a bad state, you can even connect to the database and try inserting and it will fail.
#!/bin/bash
DB_USER='root';
DB_PASSWD='root';
DB_NAME='mysql_8_bug';
TABLE_A='a';
TABLE_B='b';
set -m
#setup
mysql --user=$DB_USER --password=$DB_PASSWD << EOF
CREATE DATABASE IF NOT EXISTS $DB_NAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
DROP TABLE IF EXISTS $TABLE_A, $TABLE_B;
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
CREATE TABLE $TABLE_A (id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);
EOF
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME << EOF
CREATE TABLE $TABLE_B
(id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
int_a_id BIGINT(20) UNSIGNED DEFAULT NULL,
CONSTRAINT fk_a_id FOREIGN KEY (int_a_id) REFERENCES a (id));
EOF
#end of setup
for i in {0..100}
do
#run truncate in parallel
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="SET @@session.FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE $TABLE_A; SET @@session.FOREIGN_KEY_CHECKS = 1;" &
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="SET @@session.FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE $TABLE_B; SET @@session.FOREIGN_KEY_CHECKS = 1;" &
wait
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="INSERT INTO $TABLE_A (id) VALUES (1);"
mysql --user=$DB_USER --password=$DB_PASSWD $DB_NAME --execute="INSERT INTO $TABLE_B (int_a_id) VALUES (1);"
if [ $? -gt 0 ]
then
echo "It Happened!!! You can now check the database you will see that table a has value of id 1. The database will be in a bad state, running INSERT in table b will not work."
exit 0
fi
done
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论