Tôi có ứng dụng PHP/5.2 được điều khiển sử dụng giao dịch dưới MySQL/5.1 để có thể khôi phục nhiều lần chèn nếu gặp phải điều kiện lỗi. Tôi có các chức năng tái sử dụng khác nhau để chèn các loại mục khác nhau. Càng xa càng tốt.Giao dịch Rollback với LOCK BẢNG
Bây giờ tôi cần sử dụng khóa bảng cho một số phụ trang. Vì hướng dẫn chính thức đề xuất, tôi đang sử dụng SET autocommit=0
thay vì START TRANSACTION
vì vậy LOCK TABLES
không đưa ra cam kết ngầm định. Và, như tài liệu, mở khóa bàn ngầm cam kết bất kỳ giao dịch tích cực:
Và đây nằm vấn đề: nếu tôi chỉ đơn giản là tránh UNLOCK TABLES
, nó sẽ xảy ra rằng cuộc gọi thứ hai để LOCK TABLES
cam kết thay đổi cấp phát!
Dường như cách duy nhất là thực hiện tất cả LOCK TABLES
cần thiết trong một tuyên bố đơn lẻ. Đó là một cơn ác mộng duy trì.
Vấn đề này có giải pháp hợp lý không?
Dưới đây là một kịch bản thử nghiệm nhỏ:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
test_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
random_number INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (test_id)
)
COLLATE='utf8_spanish_ci'
ENGINE=InnoDB;
-- No table locking: everything's fine
START TRANSACTION;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
-- Table locking: everything's fine if I avoid START TRANSACTION
SET autocommit=0;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
-- Table locking: I cannot nest LOCK/UNLOCK blocks
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
UNLOCK TABLES; -- Implicit commit
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
-- Table locking: I cannot chain LOCK calls ether
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
LOCK TABLES test WRITE; -- Implicit commit
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
Tại sao bạn không cần khóa? Vấn đề thực sự là gì? –
Tôi cần khóa để đảm bảo rằng chỉ có một quy trình có thể sử dụng số thứ tự cho năm hiện tại và không còn thiếu sót nào trong chuỗi. Vấn đề thực sự là MySQL cam kết các tập dữ liệu không được xác nhận tự động khi bạn cố gắng sử dụng một tính năng không nhận biết giao dịch như khóa bảng, do đó đánh bại toàn bộ điểm của việc sử dụng các giao dịch. –
Bạn không thể sử dụng SELECT .... FOR UPDATE; ? Hoạt động tốt trong giao dịch, không có vấn đề gì cả. Sử dụng một bản ghi duy nhất cho chuỗi và cập nhật bản ghi này mỗi lần. –