[NOVÁ ODPOVĚĎ]
Děkujeme @NeverEndingQueue za to, že to přinesla. Zdá se, že MySQL tento problém konečně vyřešilo. Nejsem si jistý, ve které verzi byl tento problém poprvé opraven, ale právě teď jsem testoval s následující verzí a problém již neexistuje:
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 |
+-------------------------+------------------------------+
Aby bylo jasno:
mysql> INSERT IGNORE INTO child -> VALUES -> (NULL, 1) -> , (NULL, 2) -> , (NULL, 3) -> , (NULL, 4) -> , (NULL, 5) -> , (NULL, 6); Query OK, 4 rows affected, 2 warnings (0.03 sec) Records: 6 Duplicates: 2 Warnings: 2
Chcete-li lépe porozumět významu tohoto posledního dotazu a tomu, proč ukazuje, že je problém vyřešen, pokračujte prosím starou odpovědí níže.
[STARÁ ODPOVĚĎ]
Moje řešení je obejít problém a skutečným řešením bude vždy vyřešení problému v samotné MySQL.
Následující kroky vyřešily můj problém:
a. Zvažte použití následujících tabulek a dat:
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. Nyní potřebujeme odstranit některé řádky, abychom demonstrovali problém:
mysql>
DELETE FROM parent WHERE id IN (3, 5);
c. PROBLÉM: Problém nastane, když se pokusíte vložit následující podřízené řádky:
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)
I když IGNORE
je použito klíčové slovo, ale MySQL zruší požadovanou operaci, protože vygenerovaná chyba není přeměněna na varování (jak by měla). Nyní, když je problém zřejmý, podívejme se, jak můžeme provést poslední vložení do příkazu, aniž bychom narazili na jakoukoli chybu.
d. ŘEŠENÍ: Vlož do příkazu zabalím nějakými dalšími konstantními příkazy, které nejsou závislé ani na vložených záznamech, ani na jejich počtu.
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;
Vím, že to není optimální, ale dokud MySQL problém nevyřeší, je to nejlepší, co znám. Zejména proto, že všechny příkazy lze provést v jednom požadavku, pokud používáte knihovnu mysqli v PHP.