Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

InnoDB apenas insere registro se o id referenciado existir (sem FOREIGN KEYS)


Você pode DELETAR uma categoria somente se não for uma piada correspondente:
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;

Se houver piadas para a categoria, a junção as encontrará e, portanto, a junção externa retornará um resultado não nulo. A condição na cláusula WHERE elimina resultados não nulos, portanto, a exclusão geral corresponderá a zero linhas.

Da mesma forma, você pode INSERIR uma piada em uma categoria somente se a categoria existir:
INSERT INTO jokes (category_id, joke_text)
SELECT c.id, '$joke_text'
FROM categories AS c WHERE c.id = $category_id;

Se não houver tal categoria, o SELECT retornará zero linhas e o INSERT não será operacional.

Ambos os casos criam um bloqueio compartilhado (S-lock) na tabela de categorias.

Demonstração de um S-lock:

Em uma sessão eu corro:
mysql> INSERT INTO bar (i) SELECT SLEEP(600) FROM foo;

Na segunda sessão eu corro:
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

Você pode ver que isso cria um IS-lock na tabela foo e um S-lock em uma linha de foo, a tabela da qual estou lendo.

A mesma coisa acontece para qualquer operação híbrida de leitura/gravação, como SELECT...FOR UPDATE , INSERT...SELECT , CREATE TABLE...SELECT , para impedir que as linhas lidas sejam modificadas enquanto são necessárias como fonte para a operação de gravação.

O bloqueio IS é um bloqueio em nível de tabela que impede operações DDL na tabela, portanto, ninguém emite DROP TABLE ou ALTER TABLE enquanto esta transação depende de algum conteúdo na tabela.