Bạn chỉ có thể XÓA một danh mục nếu không phải là trò đùa phù hợp:
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;
Nếu có bất kỳ câu chuyện cười nào cho danh mục, phép nối sẽ tìm thấy chúng và do đó phép nối bên ngoài sẽ trả về kết quả khác rỗng. Điều kiện trong mệnh đề WHERE loại bỏ các kết quả không rỗng, do đó, việc xóa tổng thể sẽ khớp với không hàng.
Tương tự như vậy, bạn chỉ có thể CHÈN một câu chuyện cười vào một danh mục nếu danh mục đó tồn tại:
INSERT INTO jokes (category_id, joke_text)
SELECT c.id, '$joke_text'
FROM categories AS c WHERE c.id = $category_id;
Nếu không có danh mục như vậy, hàm SELECT trả về 0 hàng và INSERT là không chọn.
Cả hai trường hợp này đều tạo một khóa dùng chung (S-lock) trên bảng danh mục.
Trình diễn khóa S:
Trong một phiên tôi chạy:
mysql> INSERT INTO bar (i) SELECT SLEEP(600) FROM foo;
Trong phiên thứ hai, tôi chạy:
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
Bạn có thể thấy rằng điều này tạo ra khóa IS trên foo bảng và khóa S trên một hàng foo, bảng mà tôi đang đọc.
Điều tương tự cũng xảy ra đối với bất kỳ hoạt động đọc / ghi kết hợp nào như SELECT...FOR UPDATE
, INSERT...SELECT
, CREATE TABLE...SELECT
, để chặn các hàng đang đọc bị sửa đổi trong khi chúng cần làm nguồn cho thao tác ghi.
IS-lock là một khóa cấp bảng ngăn các thao tác DDL trên bảng, vì vậy không ai phát hành DROP TABLE
hoặc ALTER TABLE
trong khi giao dịch này phụ thuộc vào một số nội dung trong bảng.