Tôi có một dịch vụ web (http api) cho phép người dùng tạo tài nguyên một cách cẩn thận. Sau khi xác thực và xác thực, tôi chuyển dữ liệu sang hàm Postgres và cho phép nó kiểm tra ủy quyền và tạo các bản ghi trong cơ sở dữ liệu.
Tôi đã tìm thấy một lỗi ngày hôm nay khi hai yêu cầu http đã được thực hiện trong cùng một giây khiến cho chức năng này được gọi với dữ liệu giống hệt nhau hai lần. Có một mệnh đề bên trong hàm tạo một lựa chọn trên bảng để xem giá trị có tồn tại không, nếu nó tồn tại thì tôi lấy ID và sử dụng nó cho thao tác tiếp theo của mình, nếu không thì tôi chèn dữ liệu, lấy trở lại ID và sau đó sử dụng nó trong các hoạt động tiếp theo. Dưới đây là một ví dụ đơn giản.
select id into articleId from articles where title = 'my new blog';
if articleId is null then
insert into articles (title, content) values (_title, _content)
returning id into articleId;
end if;
-- Continue, using articleId to represent the article for next operations...
Như bạn có thể đoán, tôi đã đọc được một dữ liệu ảo trên dữ liệu nơi cả hai giao dịch được nhập vào if articleId is null then
khối và cố gắng chèn vào bảng. Một người đã thành công và người kia đã nổ tung vì một ràng buộc duy nhất trên một lĩnh vực.
Tôi đã xem xét cách bảo vệ chống lại điều này và tìm thấy một vài lựa chọn khác nhau nhưng dường như không có cách nào phù hợp với nhu cầu của chúng tôi vì một vài lý do và tôi đang vật lộn để tìm bất kỳ giải pháp thay thế nào.
insert ... on conflict do nothing/update...
Trước tiên tôi đã xem xéton conflict
tùy chọn có vẻ tốt tuy nhiên tùy chọn duy nhất làdo nothing
sau đó không trả lại ID của bản ghi đã gây ra xung đột vàdo update
sẽ không hoạt động vì nó sẽ khiến các trình kích hoạt bị loại bỏ khi trong thực tế dữ liệu không thay đổi. Trong một số trường hợp, đây không phải là vấn đề nhưng trong nhiều trường hợp, điều này có thể làm mất hiệu lực các phiên người dùng không phải là điều chúng tôi có thể làm.set transaction isolation level serializable;
đây có vẻ là câu trả lời hấp dẫn nhất, tuy nhiên ngay cả bộ thử nghiệm của chúng tôi cũng có thể gây ra sự phụ thuộc đọc / ghi, như ở trên, chúng tôi muốn chèn nếu có thứ gì đó không tồn tại và trả lại nếu có và tiếp tục thực hiện các thao tác tiếp theo. Nếu chúng tôi có một số giao dịch đang chờ xử lý chạy mã ở trên, nó sẽ gây ra lỗi phụ thuộc đọc / ghi như được nêu trong giao dịch-iso của tài liệu Postgres .
Làm thế nào để loại giao dịch đọc / ghi đồng thời này được xử lý?
Cả bản thân tôi và nhóm của tôi đều tự nhận là chuyên gia cơ sở dữ liệu, nói gì đến chuyên gia của Postgres nhưng cảm thấy như đây phải là một vấn đề được giải quyết, hoặc một người đã gặp phải trong quá khứ. Chúng tôi đang mở cho bất kỳ đề xuất. Nếu thông tin được cung cấp ở trên là không đủ, vui lòng bình luận và tôi sẽ thêm thông tin nếu cần.
if new is not distinct from old then return new; end if;
ở đầu tất cả các trình kích hoạt cập nhật của bạn.