[НОВЫЙ ОТВЕТ]
Спасибо @NeverEndingQueue за то, что подняли этот вопрос. Кажется, MySQL наконец-то исправил эту проблему. Я не уверен, в какой версии эта проблема была впервые исправлена, но сейчас я протестировал следующую версию, и проблема больше не существует:
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name | Value |
+-------------------------+------------------------------+
| innodb_version | 5.7.22 |
| protocol_version | 10 |
| slave_type_conversions | |
| tls_version | TLSv1,TLSv1.1 |
| version | 5.7.22 |
| version_comment | MySQL Community Server (GPL) |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+-------------------------+------------------------------+
Чтобы быть ясным:
mysql> INSERT IGNORE INTO child
-> VALUES
-> (NULL, 1)
-> , (NULL, 2)
-> , (NULL, 3)
-> , (NULL, 4)
-> , (NULL, 5)
-> , (NULL, 6);
Query OK, <b>4 rows affected, 2 warnings</b> (0.03 sec)
Records: 6 Duplicates: 2 Warnings: 2
Чтобы лучше понять значение этого последнего запроса и понять, почему проблема устранена, перейдите к старому ответу ниже.
[СТАРЫЙ ОТВЕТ]
Мое решение - это обход проблемы, и фактическое решение всегда будет устранять проблему в самом MySQL.
Следующие шаги решили мою проблему:
a. Рассмотрим следующие таблицы и данные:
mysql>
CREATE TABLE parent (id INT AUTO_INCREMENT NOT NULL
, PRIMARY KEY (id)
) ENGINE=INNODB;
mysql>
CREATE TABLE child (id INT AUTO_INCREMENT
, parent_id INT
, INDEX par_ind (parent_id)
, PRIMARY KEY (id)
, FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=INNODB;
mysql>
INSERT INTO parent
VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL);
mysql>
SELECT * FROM parent;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+----+
b. Теперь нам нужно удалить некоторые строки, чтобы продемонстрировать проблему:
mysql>
DELETE FROM parent WHERE id IN (3, 5);
с. ПРОБЛЕМА: Проблема возникает при попытке вставить следующие дочерние строки:
mysql>
INSERT IGNORE INTO child
VALUES
(NULL, 1)
, (NULL, 2)
, (NULL, 3)
, (NULL, 4)
, (NULL, 5)
, (NULL, 6);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint f
ails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERE
NCES `parent` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
mysql>
SELECT * FROM child;
Empty set (0.00 sec)
Несмотря на то, что используется ключевое слово IGNORE
, MySQL отменяет запрошенную операцию, поскольку сгенерированная ошибка не превращается в предупреждение (как и предполагалось). Теперь, когда проблема очевидна, давайте посмотрим, как мы можем выполнить последнюю вставку в оператор без каких-либо ошибок.
d. РЕШЕНИЕ: Я собираюсь обернуть вставку в оператор некоторыми другими константами, которые не зависят ни от вставленных записей, ни от их числа.
mysql>
SET FOREIGN_KEY_CHECKS = 0;
mysql>
INSERT INTO child
VALUES
(NULL, 1)
, (NULL, 2)
, (NULL, 3)
, (NULL, 4)
, (NULL, 5)
, (NULL, 6);
mysql>
DELETE FROM child WHERE parent_id NOT IN (SELECT id FROM parent);
mysql>
SET FOREIGN_KEY_CHECKS = 1;
Я знаю, что это не оптимально, но пока MySQL не устранил проблему, это лучшее, что я знаю. Тем более что все операторы могут быть выполнены за один запрос, если вы используете библиотеку mysqli в PHP.