Các tùy chọn của bạn là:
-
Chạy trong
SERIALIZABLE
sự cách ly. Các giao dịch phụ thuộc lẫn nhau sẽ bị hủy bỏ khi cam kết gặp lỗi tuần tự hóa. Bạn sẽ nhận được rất nhiều thư rác nhật ký lỗi và bạn sẽ phải thử lại nhiều lần, nhưng nó sẽ hoạt động một cách đáng tin cậy. -
Xác định một
UNIQUE
ràng buộc và thử lại khi không thành công, như bạn đã lưu ý. Các vấn đề tương tự như trên. -
Nếu có một đối tượng chính, bạn có thể
SELECT ... FOR UPDATE
đối tượng chính trước khi thực hiệnmax
của bạn truy vấn. Trong trường hợp này, bạnSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE
. Bạn đang sử dụngbar
làm khóa cho tất cảfoo
s vớibar_id
đó . Sau đó, bạn có thể biết rằng có thể tiếp tục an toàn, miễn là mọi truy vấn đang thực hiện tăng bộ đếm của bạn đều thực hiện điều này một cách đáng tin cậy. Điều này có thể hoạt động khá tốt.Điều này vẫn thực hiện một truy vấn tổng hợp cho mỗi cuộc gọi, điều này (cho mỗi tùy chọn tiếp theo) là không cần thiết, nhưng ít nhất nó không spam nhật ký lỗi như các tùy chọn trên.
-
Sử dụng bàn truy cập. Đây là những gì tôi muốn làm. Trong
bar
hoặc trong bảng phụ nhưbar_foo_counter
, có được ID hàng bằng cách sử dụngUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counter
hoặc tùy chọn kém hiệu quả hơn nếu khung của bạn không thể xử lý
RETURNING
:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;
Sau đó, trong cùng một giao dịch , sử dụng hàng bộ đếm đã tạo cho
number
. Khi bạn cam kết, dòng bảng bộ đếm chobar_id
đó được mở khóa cho truy vấn tiếp theo để sử dụng. Nếu bạn quay lại, thay đổi sẽ bị hủy.
Tôi đề xuất phương pháp tiếp cận bộ đếm, sử dụng bảng phụ dành riêng cho bộ đếm thay vì thêm cột vào bar
. Điều đó rõ ràng hơn để tạo mô hình và có nghĩa là bạn tạo ít khối cập nhật hơn trong bar
, điều này có thể làm chậm các truy vấn đến bar
.