Làm thế nào để truy vấn và tăng giá trị (bộ đếm) theo cách an toàn cho chuỗi? (tránh điều kiện cuộc đua)


10

Trong một bảng trong đó mỗi hàng có một bộ đếm (chỉ là một giá trị số nguyên), tôi cần lấy giá trị hiện tại và tăng nó cùng một lúc .

Hiệu quả, tôi muốn làm điều này:

SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123

Nhưng thực hiện điều này như hai truy vấn rõ ràng là không an toàn luồng: nhiều quy trình thực hiện cùng một thứ (trên cùng một hàng) có thể nhận được cùng một giá trị truy cập. Tôi cần tất cả chúng là duy nhất, vì vậy mỗi quy trình sẽ nhận được giá trị hiện tại thực tế và tăng nó lên một.

Tôi có thể nghĩ về một công trình nơi tôi thực hiện khóa thủ công mỗi hàng, nhưng tôi tự hỏi liệu có cách nào dễ dàng hơn để làm việc này không?


sử dụng giao dịch có lẽ?
ypercubeᵀᴹ

Câu trả lời:


15

Các báo cáo cập nhật hoạt động hoàn toàn tốt mà không cần chọn trước! Do định nghĩa đơn được an toàn theo định nghĩa, thậm chí hai truy vấn CẬP NHẬT được thực hiện cùng một lúc sẽ chỉ dẫn đến hàng tăng lên hai lần.

Nếu bạn thực sự muốn chọn giá trị cho tập lệnh PHP của mình, hãy làm gì đó với nó và sau đó muốn cập nhật giá trị bộ đếm chính xác này, bạn có thể làm như sau:

BEGIN;
SELECT `counter` FROM `table` WHERE `id` = 123 FOR UPDATE;
UPDATE `table` SET `counter` = `counter`+1 WHERE `id` = 123;
COMMIT;

Điều này bắt đầu một giao dịch mới, sau đó chọn các hàng bạn muốn cập nhật và khóa riêng chúng. Sau đó, bạn có thể cập nhật những người đó một cách an toàn mà không phải lo lắng về việc khách hàng khác thay đổi nội dung của họ hoặc thậm chí truy cập vào các hàng bị khóa. Cuối cùng, bạn cần phải cam kết thay đổi của bạn.

Bạn cũng nên đọc một cái gì đó về mức độ cô lập . Bạn có thể không muốn một giá trị như READ UNCOMMITTEDmức cô lập. Mọi thứ khác sẽ ổn cho trường hợp sử dụng này.


Tôi đọc ở những nơi khác UPDATE table SET counter = counter + 1là đủ nguyên tử? Bạn vẫn cần các báo cáo giao dịch xung quanh nó?
CMCDragonkai

@CMCDragonkai Chỉ riêng truy vấn của bạn là nguyên tử, nhưng nếu bạn chọn giá trị trước đó và không sử dụng FOR UPDATEvà giao dịch, giá trị bạn đã chọn có thể khác với giá trị được sử dụng trong truy vấn cập nhật. Kết hợp truy vấn của tôi sẽ khóa hàng ngay khi giá trị được chọn và do đó đảm bảo rằng giá trị bộ đếm chính xác này sẽ được sử dụng trong truy vấn cập nhật.
GhostGambler

Ok, nhưng điều đó chỉ cần thiết nếu tôi làm bất kỳ công việc nào khác ngoài việc tăng phải không? Như hiện tại, một truy vấn cập nhật nguyên tử đơn độc là đủ tốt nếu đó là tất cả những gì tôi muốn làm?
CMCDragonkai

1
@CMCDragonkai Nếu bạn không thực hiện một truy vấn khác chạm vào cột, bạn tốt.
GhostGambler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.