Je kunt een categorie alleen VERWIJDEREN als er geen overeenkomende grap is:
DELETE c FROM categories AS c
LEFT OUTER JOIN jokes AS j ON c.id=j.category_id
WHERE c.id = $category_id AND j.category_id IS NULL;
Als er grappen zijn voor de categorie, zal de join ze vinden, en daarom zal de outer join een niet-null resultaat opleveren. De voorwaarde in de WHERE-component elimineert niet-null-resultaten, dus de algehele verwijdering komt overeen met nul rijen.
Evenzo kunt u een grap alleen in een categorie INVOEGEN als de categorie bestaat:
INSERT INTO jokes (category_id, joke_text)
SELECT c.id, '$joke_text'
FROM categories AS c WHERE c.id = $category_id;
Als zo'n categorie niet bestaat, retourneert de SELECT nul rijen en is de INSERT een no-op.
Beide gevallen creëren een gedeeld slot (S-lock) op de categorieëntabel.
Demonstratie van een S-lock:
In één sessie ren ik:
mysql> INSERT INTO bar (i) SELECT SLEEP(600) FROM foo;
In de tweede sessie loop ik:
mysql> SHOW ENGINE INNODB STATUS\G
. . .
---TRANSACTION 3849, ACTIVE 1 sec
mysql tables in use 2, locked 2
2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 18, OS thread handle 0x7faefe7d1700, query id 203 192.168.56.1 root User sleep
insert into bar (i) select sleep(600) from foo
TABLE LOCK table `test`.`foo` trx id 3849 lock mode IS
RECORD LOCKS space id 22 page no 3 n bits 72 index `GEN_CLUST_INDEX` of table `test`.`foo` trx id 3849 lock mode S
Je kunt zien dat dit een IS-lock creëert op de tafelfoo, en een S-lock op een rij foo, de tafel waar ik aan het lezen ben.
Hetzelfde gebeurt voor alle hybride lees-/schrijfbewerkingen zoals SELECT...FOR UPDATE
, INSERT...SELECT
, CREATE TABLE...SELECT
, om te voorkomen dat de rijen die worden gelezen, worden gewijzigd terwijl ze nodig zijn als bron voor de schrijfbewerking.
De IS-lock is een vergrendeling op tafelniveau die DDL-bewerkingen op de tafel voorkomt, dus niemand geeft DROP TABLE
uit. of ALTER TABLE
terwijl deze transactie afhankelijk is van bepaalde inhoud in de tabel.