Bất cứ khi nào bạn yêu cầu SERIALIZABLE
cô lập DB sẽ cố gắng tạo các tập hợp truy vấn đồng thời dường như đã được thực thi tuần tự xét về kết quả mà họ tạo ra. Điều này không phải lúc nào cũng có thể thực hiện được, ví dụ:khi hai giao dịch có sự phụ thuộc lẫn nhau. Trong trường hợp này, PostgreSQL sẽ hủy bỏ một trong các giao dịch với lỗi tuần tự hóa thất bại, cho bạn biết rằng bạn nên thử lại.
Mã sử dụng SERIALIZABLE
luôn phải chuẩn bị để thử lại các giao dịch. Nó phải kiểm tra SQLSTATE
và, đối với các lỗi tuần tự hóa, hãy lặp lại giao dịch.
Xem tài liệu cách ly giao dịch .
Trong trường hợp này, tôi nghĩ rằng sự hiểu lầm chính của bạn có thể là:
vì nó không có gì thuộc loại này, nó là một INSERT ... SELECT
chạm vào vo_business.repositoryoperation
cho cả đọc và viết. Như vậy là đủ để tạo ra sự phụ thuộc tiềm năng với một giao dịch khác cũng thực hiện tương tự hoặc một giao dịch đọc và ghi vào bảng theo cách khác.
Ngoài ra, mã cách ly có thể nối tiếp hóa trong một số trường hợp có thể khử tạo thành thông tin phụ thuộc cấp khối giữ vì lý do hiệu quả. Vì vậy, nó có thể không nhất thiết phải là một giao dịch chạm vào các hàng giống nhau, chỉ là cùng một khối lưu trữ, đặc biệt là khi đang tải.
PostgreSQL sẽ thích hủy bỏ một giao dịch có thể tuần tự hóa nếu nó không chắc chắn rằng nó an toàn. Hệ thống chứng minh có những hạn chế. Vì vậy, cũng có thể bạn vừa tìm thấy một trường hợp đánh lừa nó.
Để biết chắc chắn, tôi cần xem cả hai giao dịch song song với nhau, nhưng đây là bằng chứng cho thấy một insert ... select
có thể xung đột với bản thân của nó. Mở ba psql
phiên và chạy:
session0: CREATE TABLE serialdemo(x integer, y integer);
session0: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session0: LOCK TABLE serialdemo IN ACCESS EXCLUSIVE MODE;
session1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session2: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
session1: INSERT INTO serialdemo (x, y)
SELECT 1, 2
WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);
session2: INSERT INTO serialdemo (x, y)
SELECT 1, 2
WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);
session0: ROLLBACK;
session1: COMMIT;
session2: COMMIT;
session1 sẽ cam kết tốt. session2 sẽ không thành công với:
ERROR: could not serialize access due to read/write dependencies among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
HINT: The transaction might succeed if retried.
Đó không phải là lỗi tuần tự hóa giống như trường hợp của bạn và không chứng minh rằng của bạn các câu lệnh có thể xung đột với nhau, nhưng nó cho thấy rằng một insert ... select
không phải là nguyên tử như bạn nghĩ.