Tôi phát triển một hệ thống đặt chỗ trực tuyến. Để đơn giản hóa, giả sử người dùng có thể đặt nhiều mục và mỗi mục chỉ có thể được đặt một lần. Các mục được thêm vào giỏ hàng đầu tiên.Cách sử dụng đúng các giao dịch và khóa để đảm bảo tính toàn vẹn của cơ sở dữ liệu?
Ứng dụng sử dụng MySql
/InnoDB
cơ sở dữ liệu. Theo tài liệu MySql, mức cô lập mặc định là Repeatable reads
.
Dưới đây là thủ tục thanh toán tôi đã đưa ra cho đến nay:
- Bắt đầu giao dịch
- Chọn các mục trong giỏ hàng mua sắm (với
for update
khóa)
ghi từcart-item
vàitems
bảng được tìm nạp ở bước này.- Kiểm tra xem các mặt hàng chưa được đặt bởi bất kỳ ai khác
Kiểm tra cơ bản nếuquantity > 0
. Nó phức tạp hơn trong ứng dụng thực tế, do đó tôi đặt nó ở đây như một bước riêng biệt.- Cập nhật các mục, đặt
quantity = 0
Cũng thực hiện các thao tác cơ sở dữ liệu cần thiết khác.- Thanh toán (qua api bên ngoài như PayPal hoặc sọc)
Không cần tương tác với người dùng vì chi tiết thanh toán có thể được thu trước khi thanh toán.- Nếu mọi thứ diễn ra tốt đẹp cam kết giao dịch hoặc rollback khác
- Tiếp tục với logic không cần thiết
Gửi e-mail vv trong trường hợp thành công, chuyển hướng cho lỗi.
Tôi không chắc liệu điều đó có đủ hay không. Tôi lo lắng liệu:
- Người dùng khác cố gắng đặt cùng một mục cùng một lúc sẽ được xử lý đúng. Giao dịch của anh ta
T2
có chờ đến khiT1
được thực hiện không? - Thanh toán bằng PayPal hoặc Stripe có thể mất chút thời gian. Điều này sẽ không trở thành vấn đề về hiệu suất?
- Tính khả dụng của các mục sẽ được hiển thị chính xác mọi lúc (các mục sẽ khả dụng cho đến khi thanh toán thành công). Những lựa chọn chỉ đọc này có sử dụng
shared lock
không? - Có thể MySql rollbacks tự giao dịch không? Có tốt hơn là thử lại tự động hoặc hiển thị thông báo lỗi và cho phép người dùng thử lại không?
- Tôi đoán là đủ nếu tôi làm
SELECT ... FOR UPDATE
trên bảngitems
. Bằng cách này, cả hai yêu cầu gây ra bởi nhấp đúp chuột và người dùng khác sẽ phải chờ cho đến khi giao dịch kết thúc. Họ sẽ chờ đợi vì họ cũng sử dụngFOR UPDATE
. Trong khi đó, vanillaSELECT
sẽ chỉ nhìn thấy ảnh chụp nhanh của db trước giao dịch, mặc dù không có sự chậm trễ, phải không? - Nếu tôi sử dụng
JOIN
trongSELECT ... FOR UPDATE
, sẽ ghi lại trong cả hai bảng sẽ bị khóa? - Tôi hơi bối rối về CHỌN ... CẬP NHẬT trên các hàng không tồn tại phần câu trả lời của Willem Renzema. Khi nào nó có thể trở nên quan trọng? Bạn có thể cung cấp bất kỳ ví dụ nào không?
Dưới đây là một số tài nguyên Tôi đã đọc: How to deal with concurrent updates in databases?, MySQL: Transactions vs Locking Tables, Do database transactions prevent race conditions?, Isolation (database systems), InnoDB Locking and Transaction Model, A beginner’s guide to database locking and the lost update phenomena.
Viết lại câu hỏi ban đầu của tôi để làm cho câu hỏi tổng quát hơn.
Đã thêm câu hỏi tiếp theo.
Câu hỏi quan trọng: Khi bạn 'CHỌN ... ĐỂ CẬP NHẬT ', bạn có đang chọn một hàng bạn biết đã tồn tại hay không, nơi bạn định chèn hàng? –
@WillemRenzema Tôi chỉ chọn các hàng đã tồn tại thông qua bảng tổng hợp 'cart-item' – Paul