Một tuyên bố như thế hoạt động tương tự với MyISAM hoặc InnoDB, với một giao dịch hoặc với autocommit = ON. Nó chặn đủ để thực hiện truy vấn, do đó chặn kết nối khác. Khi kết thúc, kết nối khác tiến hành. Trong mọi trường hợp, cột sẽ sớm giảm 11.
Người dùng thứ ba có thể thấy giá trị giảm đi 0 hoặc 4 hoặc 7 hoặc 11. "Thời gian rất chính xác" là không thực sự có thể bởi vì, tại một số điểm trong quá trình thực thi của mỗi câu lệnh, khóa đơn được kiểm tra / đặt / bất cứ điều gì . Đó là, chúng sẽ được nối tiếp, nhanh đến mức bạn không thể nhìn thấy nó.
InnoDB chỉ khóa các hàng, không phải bảng. (OK, câu lệnh DDL làm khóa táo bạo hơn.)
Điều thú vị hơn là một giao dịch sửa đổi hai điều hoặc mất một khoảng thời gian đáng chú ý:
Trường hợp có ý định: Một mục nhưng mất thời gian:
BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;
Lựa chọn cần phải được viết như vậy:
SELECT something FOR UPDATE;
Điều này nói với các kết nối khác "Tôi dự định cập nhật hàng; xin đừng làm phiền tôi". (Tôi đưa ra ví dụ này, vì rất nhiều người mới bỏ lỡ sự tinh tế này.)
Trường hợp bế tắc: Lộn xộn với 2 điều:
BEGIN; -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;
BEGIN; -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;
Đây là ví dụ kinh điển về sự bế tắc - mỗi người nắm lấy một thứ và sau đó tìm đến thứ khác. Rõ ràng nó không thể được thực hiện để làm việc. Một giao dịch bị giết; cái khác hoàn thành. Do đó, bạn phải kiểm tra lỗi, để bạn có thể khám phá nó.
Phản ứng bình thường đối với bế tắc là phát lại toàn bộ giao dịch thất bại. Đến lúc đó, kết nối khác sẽ không bị can thiệp và nó sẽ tiếp tục mà không gặp sự cố. (OK, nhưng một kết nối khác có thể tạo ra một bế tắc khác.)
Trường hợp trễ: Nếu hai kết nối lấy nhiều thứ theo cùng một thứ tự, thì một kết nối có thể bị trì hoãn cho đến khi kết nối khác kết thúc. Để giữ điều này khỏi "chờ đợi mãi mãi", có 50 giây mặc định innodb_lock_wait_timeout
. Cặp đơn giản của bạn UPDATEs
thực sự là một ví dụ về trường hợp này. Một sẽ kết thúc kịp thời; cái khác bị đình trệ cho đến khi kết thúc đầu tiên.
Lưu ý cách Deadlock có thể (trong một số trường hợp) được chuyển thành Trì hoãn bằng cách liên tục yêu cầu những thứ bạn chạm vào.
autocommit = 1: Với cài đặt này và không cần gọi BEGIN
, mỗi câu lệnh đều có hiệu quả:
BEGIN;
your statement
COMMIT;
autocommit = 0: Đây là sự cố đang chờ xảy ra. Khi bạn thực hiện một truy vấn ghi, một BEGIN
được ngầm định tạo ra. Tuy nhiên, trách nhiệm của bạn là cuối cùng phát hành COMMIT
. Nếu bạn không làm như vậy, bạn sẽ tự hỏi tại sao hệ thống của bạn bị treo. (Một lỗi người mới phổ biến khác.) Lời khuyên của tôi: "Không bao giờ sử dụng =0
".