Sự cố bạn đang gặp phải xảy ra vì MySQL không chỉ khóa hàng của bảng cho một giá trị bạn sẽ chèn, nó khóa tất cả các giá trị có thể có giữa id
trước đó và id tiếp theo theo thứ tự, vì vậy, hãy sử dụng lại ví dụ dưới đây của bạn:
DROP TABLE IF EXISTS foo;
CREATE TABLE `foo` (
`i` INT(11) NOT NULL,
`j` INT(11) DEFAULT NULL,
PRIMARY KEY (`i`),
UNIQUE KEY `jk` (`j`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO foo VALUES (5,5), (8,8), (11,11);
Giả sử bạn bắt đầu với giao dịch TX1:
START TRANSACTION;
REPLACE INTO foo VALUES(8,8);
Sau đó, nếu bạn bắt đầu một giao dịch TX2
, bất cứ điều gì INSERT
hoặc REPLACE
sử dụng id
từ 5 đến 11 sẽ bị khóa:
START TRANSACTION;
REPLACE INTO foo VALUES(11,11);
Có vẻ như MySQL sử dụng loại khóa này để tránh "vấn đề ma" được mô tả ở đây: http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html , MySQL sử dụng "khóa tiếp theo", kết hợp khóa hàng chỉ mục với khóa khoảng cách, điều này có nghĩa là đối với chúng tôi, nó sẽ khóa rất nhiều id có thể có giữa id trước đó và id tiếp theo, đồng thời cũng sẽ khóa id trước đó và tiếp theo .
Để tránh điều này, hãy thử tạo một thuật toán máy chủ chèn các bản ghi của bạn để các bản ghi được chèn trong các giao dịch khác nhau không trùng lặp hoặc ít nhất là không thực hiện tất cả các giao dịch của bạn cùng một lúc nên TX
không phải đợi nhau.