Khi nào nên sử dụng CHỌN CẬP NHẬT CHO CẬP NHẬT?


118

Xin hãy giúp tôi hiểu trường hợp sử dụng phía sau SELECT ... FOR UPDATE.

Câu hỏi 1 : Đây có phải là một ví dụ tốt về thời điểm SELECT ... FOR UPDATEnên sử dụng?

Được:

  • phòng [id]
  • thẻ [id, tên]
  • room_tags [room_id, tag_id]
    • room_id và tag_id là khóa ngoại

Ứng dụng muốn liệt kê tất cả các phòng và thẻ của họ, nhưng cần phân biệt giữa các phòng không có thẻ so với các phòng đã bị xóa. Nếu CHỌN ... ĐỂ CẬP NHẬT không được sử dụng, điều có thể xảy ra là:

  • Ban đầu:
    • phòng chứa [id = 1]
    • thẻ chứa [id = 1, name = 'cats']
    • room_tags chứa [room_id = 1, tag_id = 1]
  • Chủ đề 1: SELECT id FROM rooms;
    • returns [id = 1]
  • Chủ đề 2: DELETE FROM room_tags WHERE room_id = 1;
  • Chủ đề 2: DELETE FROM rooms WHERE id = 1;
  • Chủ đề 2: [cam kết giao dịch]
  • Chủ đề 1: SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
    • trả về một danh sách trống

Bây giờ Chủ đề 1 nghĩ rằng phòng 1 không có thẻ, nhưng thực tế phòng đã bị xóa. Để giải quyết vấn đề này, Thread 1 nên SELECT id FROM rooms FOR UPDATE, do đó ngăn chặn Thread 2 xóa từ roomscho đến khi Thread 1 được thực hiện. Đúng không?

Câu 2 : Khi nào nên sử dụng SERIALIZABLEcách ly giao dịch so READ_COMMITTEDvới SELECT ... FOR UPDATE?

Câu trả lời dự kiến ​​sẽ có thể mang theo (không phải cơ sở dữ liệu cụ thể). Nếu điều đó là không thể, xin vui lòng giải thích tại sao.


2
Bạn đang sử dụng RDBMS nào?
Quassnoi

2
@Quassnoi, như đã đề cập ở dưới cùng của câu hỏi, tôi đang tìm kiếm một giải pháp di động (không dành riêng cho cơ sở dữ liệu).
Gili

2
Là các tùy chọn REPEATABLE_READREAD_COMMITTEDthậm chí tùy chọn di động? Kết quả duy nhất tôi nhận được cho những người đó là cho máy chủ MSSQL
Billy ONeal

3
@BillyONeal: lưu ý rằng các chế độ cách ly đảm bảo rằng bạn không thấy các quirks mà chúng không cho phép, nhưng không nói gì về các quirks mà chúng cho phép. Điều này có nghĩa là cài đặt, giả sử, READ COMMITTEDchế độ không xác định liệu bạn có thực sự nhìn thấy các bản ghi được cam kết bởi một giao dịch khác hay không: nó chỉ đảm bảo bạn sẽ không bao giờ thấy các bản ghi không được cam kết.
Quassnoi

3
Một select ... for updatetrên roomsvẫn sẽ cho phép room_tagsđược xóa bởi vì họ là các bảng riêng biệt. Bạn có nghĩa là hỏi liệu for updateđiều khoản sẽ ngăn chặn xóa rooms?
Chris Saxon

Câu trả lời:


83

Cách di động duy nhất để đạt được sự thống nhất giữa các phòng và thẻ và đảm bảo các phòng không bao giờ bị trả lại sau khi chúng bị xóa là khóa chúng lại SELECT FOR UPDATE.

Tuy nhiên, trong một số hệ thống, khóa là tác dụng phụ của kiểm soát đồng thời và bạn đạt được kết quả tương tự mà không chỉ định FOR UPDATErõ ràng.


Để giải quyết vấn đề này, Thread 1 nên SELECT id FROM rooms FOR UPDATE, do đó ngăn chặn Thread 2 xóa từ roomscho đến khi Thread 1 được thực hiện. Đúng không?

Điều này phụ thuộc vào điều khiển đồng thời hệ thống cơ sở dữ liệu của bạn đang sử dụng.

  • MyISAMtrong MySQL(và một số hệ thống cũ khác) sẽ khóa toàn bộ bảng trong suốt thời gian của truy vấn.

  • Trong SQL Server, SELECTcác truy vấn đặt các khóa được chia sẻ trên các bản ghi / trang / bảng mà chúng đã kiểm tra, trong khi DMLcác truy vấn đặt các khóa cập nhật (sau này được thăng cấp thành độc quyền hoặc hạ cấp thành các khóa chung). Các khóa độc quyền không tương thích với các khóa được chia sẻ, do đó, SELECThoặc DELETEtruy vấn sẽ khóa cho đến khi một phiên khác cam kết.

  • Trong cơ sở dữ liệu mà sử dụng MVCC(như Oracle, PostgreSQL, MySQLvới InnoDB), một DMLtruy vấn tạo ra một bản sao của hồ sơ (trong một hoặc một cách khác) và nói chung là độc giả không chặn các tác giả và ngược lại. Đối với các cơ sở dữ liệu này, SELECT FOR UPDATEsẽ có ích: nó sẽ khóa SELECThoặc DELETEtruy vấn cho đến khi một phiên khác được thực hiện, giống như SQL Servervậy.

Khi nào nên sử dụng REPEATABLE_READcách ly giao dịch so READ_COMMITTEDvới SELECT ... FOR UPDATE?

Nói chung, REPEATABLE READkhông cấm các hàng ảo (các hàng xuất hiện hoặc biến mất trong một giao dịch khác, thay vì được sửa đổi)

  • Trong Oraclecác PostgreSQLphiên bản trước đó , REPEATABLE READthực sự là một từ đồng nghĩa với SERIALIZABLE. Về cơ bản, điều này có nghĩa là giao dịch không thấy các thay đổi được thực hiện sau khi nó bắt đầu. Vì vậy, trong thiết lập này, Thread 1truy vấn cuối cùng sẽ trả về phòng như thể nó chưa bao giờ bị xóa (có thể hoặc không thể là những gì bạn muốn). Nếu bạn không muốn hiển thị các phòng sau khi chúng bị xóa, bạn nên khóa các hàng bằngSELECT FOR UPDATE

  • Trong InnoDB, REPEATABLE READSERIALIZABLEnhững thứ khác nhau: độc giả trong SERIALIZABLEchế độ thiết lập khóa tiếp theo-key trên hồ sơ mà họ đánh giá, ngăn chặn có hiệu quả đồng thời DMLtrên chúng. Vì vậy, bạn không cần một SELECT FOR UPDATEchế độ nối tiếp, nhưng cần chúng trong REPEATABLE READhoặc READ COMMITED.

Lưu ý rằng tiêu chuẩn về các chế độ cách ly quy định rằng bạn không nhìn thấy các quirks nhất định trong các truy vấn của mình nhưng không xác định cách thức (có khóa hoặc có MVCChoặc bằng cách khác).

Khi tôi nói "bạn không cần SELECT FOR UPDATE" tôi thực sự nên thêm vào "vì các tác dụng phụ của việc triển khai công cụ cơ sở dữ liệu nhất định".


1
Điểm cuối cùng là mấu chốt của vấn đề, tôi nghĩ: "bạn không cần CHỌN CẬP NHẬT ở chế độ tuần tự hóa, nhưng cần chúng ở chế độ ĐỌC LẠI ĐỌC hoặc ĐỌC".
Colin 't Hart

Bạn đúng. Câu hỏi thứ hai nên được hỏi khi nào SERIALIZABLEnên được sử dụng so READ_COMMITTEDvới SELECT ... FOR UPDATE. Bạn có thể vui lòng cập nhật câu trả lời của bạn để phản ánh câu hỏi cập nhật này?
Gili

1
@Gili: "bạn không cần SELECT FOR UPDATEở chế độ tuần tự hóa", với InnoDB. Với các MVCChệ thống khác , hai hệ thống này là từ đồng nghĩa và bạn cần SELECT FOR UPDATE.
Quassnoi

1
Tôi thấy bài đăng của Colin trả lời các câu hỏi cụ thể của tôi tốt hơn câu trả lời của bạn nhưng tôi đánh giá cao tất cả các tài liệu tham khảo bạn cung cấp. Tôi sẽ chấp nhận một câu trả lời kết hợp tốt nhất cả hai (câu trả lời cụ thể ở trên, hỗ trợ các tài liệu tham khảo bên dưới).
Gili

This depends on the concurrency control your database system is using: Tôi nghĩ rằng bạn đang chia tóc. Tất cả các trường hợp mà bạn liệt kê dưới đây nói rằng phòng không bị xóa giữa SELECTđến cuối giao dịch. Vì vậy, không nên trả lời đơn giản Yesvới các tài liệu tham khảo hỗ trợ dưới đây?
Gili

33

Câu trả lời ngắn:

Q1: Có.

Q2: Không quan trọng bạn sử dụng cái gì.

Câu trả lời dài:

Một select ... for updatedi chúc (như ngụ ý) chọn một số hàng nhất định nhưng cũng khóa chúng như thể chúng đã được cập nhật bởi giao dịch hiện tại (hoặc như thể cập nhật danh tính đã được thực hiện). Điều này cho phép bạn cập nhật lại chúng trong giao dịch hiện tại và sau đó cam kết, mà không có giao dịch nào khác có thể sửa đổi các hàng này theo bất kỳ cách nào.

Một cách khác để xem xét nó, như thể hai câu lệnh sau được thực thi nguyên tử:

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;

Vì các hàng bị ảnh hưởng bởi my_conditionbị khóa, không có giao dịch nào khác có thể sửa đổi chúng theo bất kỳ cách nào và do đó, mức độ cô lập giao dịch không tạo ra sự khác biệt ở đây.

Cũng lưu ý rằng mức cô lập giao dịch không phụ thuộc vào khóa: đặt mức cô lập khác không cho phép bạn xoay quanh việc khóa và cập nhật các hàng trong một giao dịch khác bị khóa bởi giao dịch của bạn.

Những mức cô lập giao dịch nào đảm bảo (ở các mức khác nhau) là tính nhất quán của dữ liệu trong khi các giao dịch đang được tiến hành.


1
Tôi nghĩ What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.không chính xác ngụ ý rằng mức độ cô lập không ảnh hưởng đến những gì xảy ra trong một giao dịch. Tôi khuyên bạn nên sửa đổi phần này và cung cấp thêm chi tiết về cách chúng ảnh hưởng đến những gì bạn thấy (hoặc không nhìn thấy) trong khi giao dịch.
Gili

1
Tôi thấy bài đăng của bạn trả lời các câu hỏi cụ thể của tôi tốt hơn Quassnoi nhưng tôi đánh giá cao tất cả các tài liệu tham khảo mà anh ấy cung cấp. Tôi sẽ chấp nhận một câu trả lời kết hợp tốt nhất cả hai (câu trả lời cụ thể ở trên, hỗ trợ các tài liệu tham khảo bên dưới).
Gili

Khóa và cách ly là phức tạp thay thế cho nhau. Vậy có cuốn sách nào để có kiến ​​thức về điều đó không?
Chao
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.