Chuyển đến nội dung chính
Mô-đun 11 · Bài học 3 trong tổng số 443/57 trong khóa học~15 min
Bài học theo mô-đun (3/4)

Khóa và CHỌN ĐỂ CẬP NHẬT

Hiểu cách cơ sở dữ liệu hoạt động độc lập trên một thiết bị đầu cuối rất đơn giản...đợi đã, tôi đã nói rồi! Đôi khi "Cập nhật nguyên tử" (ví dụ: stock = stock - 1) là không đủ.

Hãy tưởng tượng bạn phải kiểm tra xem người dùng có đủ số dư để mua những thứ trị giá 50 € hay không:

  1. SELECT balance FROM users WHERE id = 1;
  2. JS: Nếu số dư < 50, hãy chặn chúng!
  3. Nếu không thì tiến hành thanh toán...
  4. Chạy khấu trừ! (Và ở đây, bạn tìm thấy một người dùng, trong khi xác thực séc ở bước 2, đã thực hiện một séc song song khác đã đốt cháy tài khoản của họ và bây giờ bạn đang ở mức dưới 0!).

ĐỂ CẬP NHẬT Khóa rõ ràng

Việc thêm FOR UPDATE vào cuối SELECT sẽ biến lần đọc vô tội của bạn thành một Khóa kín đối với các ứng dụng khách khác một cách kỳ diệu cho đến lần CAM KẾT tiếp theo. Không ai khác có thể thực hiện CẬP NHẬT (hoặc đọc để cập nhật đồng thời) trên các hàng đã chọn cụ thể đó cho đến khi bạn quyết định phải làm gì với chúng!

SQL
BEGIN;

-- If id=3 had already been locked by T1, T2 will sit in perpetual loading on this "read"
-- frozen in place, before receiving the raw data, until T1 runs COMMIT freeing everyone!
SELECT balance
FROM users
WHERE id = 3
FOR UPDATE;

-- at this point our Node JS instance lives with the guarantee, knowing for certain that NO ONE ELSE in the world has
-- manipulated (nor been able to read with intent to alter) that balance while we complete the application logic

UPDATE users SET balance = balance - 50 WHERE id = 3;

COMMIT;

Thậm chí còn có FOR SHARE cho phép những người đọc khác tiếp tục đọc (nếu ở khóa cơ sở) mà không chặn các lần đọc trạng thái nhưng chặn mọi cập nhật có thể có tiếp theo cho đến khi bạn cam kết. Tuy nhiên, để sửa đổi, hãy luôn sử dụng sức mạnh của mệnh đề khóa độc quyền:

Hãy tự mình thử

tập thể dục#sql.m11.l3.e1
Nỗ lực: 0Đang tải…

Mở một giao dịch trong phạm vi thời gian thông thường và khóa riêng việc đọc ID sản phẩm=5.\nChạy truy vấn hai bước:\n1. Mở giao dịch (BEGIN)\n2. Truy vấn 'sản phẩm' tìm nạp hàng đầy đủ cho ID 5 với sự đảm bảo rằng không ai sẽ thay đổi nó bằng cách đính kèm tùy chọn 'CẬP NHẬT'.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

BEGIN;, dòng mới, CHỌN * TỪ các sản phẩm WHERE id = 5 ĐỂ CẬP NHẬT;

Giải pháp khả dụng sau 3 lần thử

tập thể dục#sql.m11.l3.e2
Nỗ lực: 0Đang tải…

Đôi khi giao dịch bị treo trong những khoảng thời gian tai hại (Bế tắc hoặc chờ vô hạn).\nĐể tránh điều này, bạn có thể ra lệnh cho cơ sở dữ liệu từ bỏ thời điểm hàng không có sẵn ngay lập tức: sử dụng NOWAIT ở cuối, điều này sẽ khiến ngoại lệ máy chủ SQL quay trở lại JS để được bắt thử mà không bị treo vĩnh viễn.\nChạy SELECT cho danh mục ID=1 và sử dụng FOR UPDATE nhưng thực thi NOWAIT.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

CHỌN * TỪ danh mục WHERE id = 1 ĐỂ CẬP NHẬT NGAY BÂY GIỜ;

Giải pháp khả dụng sau 3 lần thử