Можете да ИЗТРИЙТЕ категория само ако не е подходяща шега:
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;
Ако има някакви шеги за категорията, присъединяването ще ги намери и следователно външното присъединяване ще върне ненулев резултат. Условието в клаузата WHERE елиминира ненулеви резултати, така че цялостното изтриване ще съответства на нула редове.
По същия начин можете да ВМЕСИТЕ шега в категория само ако категорията съществува:
INSERT INTO jokes (category_id, joke_text)
SELECT c.id, '$joke_text'
FROM categories AS c WHERE c.id = $category_id;
Ако няма такава категория, SELECT връща нула редове, а INSERT е без операция.
И двата случая създават споделено заключване (S-lock) на таблицата с категории.
Демонстрация на S-заключване:
В една сесия изпълнявам:
mysql> INSERT INTO bar (i) SELECT SLEEP(600) FROM foo;
Във втората сесия изпълнявам:
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
Можете да видите, че това създава IS-заключване на таблицата foo и S-заключване на един ред foo, таблицата, от която чета.
Същото нещо се случва за всякакви хибридни операции за четене/запис, като SELECT...FOR UPDATE
, INSERT...SELECT
, CREATE TABLE...SELECT
, за да блокирате промяната на редовете, които се четат, докато са необходими като източник за операцията за запис.
IS-lock е заключване на ниво таблица, което предотвратява DDL операции на таблицата, така че никой не издава DROP TABLE
или ALTER TABLE
докато тази транзакция зависи от някакво съдържание в таблицата.