Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

SELECT FOR UPDATE có ngăn chặn các kết nối khác chèn khi hàng không có mặt không?

MySQL

CHỌN ... ĐỂ CẬP NHẬT với CẬP NHẬT

Sử dụng các giao dịch với InnoDB (tự động cam kết đã tắt), SELECT ... FOR UPDATE cho phép một phiên tạm thời khóa một bản ghi (hoặc các bản ghi) cụ thể để không có phiên nào khác có thể cập nhật nó. Sau đó, trong cùng một giao dịch, phiên thực sự có thể thực hiện UPDATE trên cùng một bản ghi và cam kết hoặc quay trở lại giao dịch. Điều này sẽ cho phép bạn khóa bản ghi để không phiên nào khác có thể cập nhật nó trong khi có lẽ bạn thực hiện một số logic nghiệp vụ khác.

Điều này được thực hiện với khóa. InnoDB sử dụng các chỉ mục để khóa các bản ghi, vì vậy việc khóa một bản ghi hiện có có vẻ dễ dàng - chỉ cần khóa chỉ mục cho bản ghi đó.

CHỌN ... ĐỂ CẬP NHẬT với CHÈN

Tuy nhiên, để sử dụng SELECT ... FOR UPDATE với INSERT , làm cách nào để khóa chỉ mục cho một bản ghi chưa tồn tại? Nếu bạn đang sử dụng mức cô lập mặc định của REPEATABLE READ , InnoDB cũng sẽ sử dụng khoảng cách ổ khóa. Miễn là bạn biết id (hoặc thậm chí nhiều id) để khóa, sau đó InnoDB có thể khóa khoảng trống để không có bản ghi nào khác có thể được chèn vào khoảng trống đó cho đến khi chúng tôi hoàn thành nó.

Nếu id của bạn là cột tăng tự động, sau đó là SELECT ... FOR UPDATE với INSERT INTO sẽ có vấn đề vì bạn không biết id mới là gì cho đến khi bạn chèn nó vào. Tuy nhiên, vì bạn biết id mà bạn muốn chèn, SELECT ... FOR UPDATE với INSERT sẽ hoạt động.

CAVEAT

Ở mức cách ly mặc định, SELECT ... FOR UPDATE trên một bản ghi không tồn tại thì không chặn các giao dịch khác. Vì vậy, nếu cả hai giao dịch đều thực hiện SELECT ... FOR UPDATE trên cùng một bản ghi chỉ mục không tồn tại, cả hai đều sẽ nhận được khóa và không giao dịch nào có thể cập nhật bản ghi. Trên thực tế, nếu họ cố gắng, sẽ phát hiện ra một bế tắc.

Do đó, nếu bạn không muốn gặp bế tắc, bạn có thể làm như sau:

CHÈN VÀO ...

Bắt đầu giao dịch và thực hiện INSERT . Thực hiện logic kinh doanh của bạn và cam kết hoặc khôi phục giao dịch. Ngay sau khi bạn thực hiện INSERT trên chỉ mục bản ghi không tồn tại trong giao dịch đầu tiên, tất cả các giao dịch khác sẽ chặn nếu chúng cố gắng INSERT một bản ghi có cùng chỉ mục duy nhất. Nếu giao dịch thứ hai cố gắng chèn một bản ghi có cùng chỉ mục sau khi giao dịch đầu tiên thực hiện việc chèn, thì nó sẽ gặp lỗi "khóa trùng lặp". Xử lý phù hợp.

CHỌN ... KHÓA CHẾ ĐỘ CHIA SẺ

Nếu bạn chọn bằng LOCK IN SHARE MODE trước INSERT , nếu giao dịch trước đó đã chèn bản ghi đó nhưng chưa được cam kết, thì SELECT ... LOCK IN SHARE MODE sẽ chặn cho đến khi giao dịch trước đó hoàn tất.

Vì vậy, để giảm nguy cơ trùng lặp các lỗi khóa, đặc biệt nếu bạn giữ ổ khóa một lúc trong khi thực hiện logic nghiệp vụ trước khi thực hiện hoặc khôi phục chúng:

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Nếu không có bản ghi nào được trả lại thì
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tại sao mệnh đề IN oracle chỉ có giới hạn 1000 đối với dữ liệu tĩnh?

  2. Phân tích cú pháp chuỗi phân cách bằng đường ống thành cột?

  3. Trả về kết quả ngay cả cho các phần tử trong danh sách IN không tồn tại trong bảng

  4. CẬP NHẬT câu lệnh trong Oracle bằng cách sử dụng SQL hoặc PL / SQL để CHỈ cập nhật hàng trùng lặp đầu tiên

  5. Cập nhật một bảng trong Oracle nếu bất kỳ giá trị trường nào là rỗng và xác định rằng cập nhật thành công