Có hai cách tiếp cận chung để khóa.
Đầu tiên, bạn có khóa bi quan. Trong cách tiếp cận này, bạn khóa hàng (SELECT ... FOR UPDATE
) ngăn không cho bất kỳ ai khác thay đổi hàng. Sau đó, bạn thực hiện UPDATE
. Khi bạn thực hiện thay đổi của mình, khóa sẽ được giải phóng. Trong trường hợp này không cần thiết phải có số phiên bản / cột dấu thời gian (ít nhất là không hỗ trợ khóa) và mã tương đối dễ dàng.
Nhược điểm của khóa bi quan là bạn cần phải giữ khóa trong suốt thời gian người dùng đang ngồi trên một trang có khả năng chỉnh sửa dữ liệu. Về mặt kỹ thuật, điều này thực sự khó nếu bạn đang xây dựng một ứng dụng dựa trên web vì HTTP là một giao thức không trạng thái. Yêu cầu ban đầu hiển thị trang thường sẽ nhận được kết nối từ nhóm kết nối, hãy thực hiện SELECT
, và sau đó trả lại kết nối cho nhóm sau khi trang hoàn tất. Yêu cầu cập nhật dữ liệu tiếp theo thường sẽ xảy ra trên một kết nối khác với một phiên cơ sở dữ liệu khác, vì vậy bạn không thể khóa hàng trong phiên đầu tiên và cập nhật nó trong phiên thứ hai. Nếu bạn muốn khóa hàng một cách bi quan, bạn cần phải làm nhiều việc ở phần cuối để đảm bảo rằng một kết nối cơ sở dữ liệu được gắn với một phiên tầng giữa cụ thể cho đến khi người dùng chỉnh sửa xong dữ liệu. Điều này nói chung có tác động rất tiêu cực đến khả năng mở rộng và gây ra tất cả các loại vấn đề quản lý phiên - làm thế nào bạn biết, chẳng hạn như, làm thế nào để bạn biết liệu tôi đã yêu cầu một trang, khóa một hàng và sau đó đóng trình duyệt của mình mà không bao giờ đăng xuất hoặc thực hiện thay đổi? Bạn định để bản ghi bị khóa trong cơ sở dữ liệu trong bao lâu? Điều gì xảy ra nếu một số phiên khác đang cố gắng khóa hàng? Bạn định để phiên đó chờ khóa trong bao lâu nếu người đầu tiên đi ăn trưa? Nói chung, mọi người không thực hiện khóa bi quan trong các ứng dụng dựa trên web bởi vì việc quản lý phiên và trạng thái phiên là quá phi thực tế.
Tùy chọn thứ hai là khóa lạc quan. Trong cách tiếp cận này, bạn thêm số phiên bản / dấu thời gian vào hàng. Bạn chọn số phiên bản / dấu thời gian này khi bạn truy vấn dữ liệu. Sau đó, bạn sử dụng nó trong WHERE
của bạn khi bạn cập nhật sau đó và kiểm tra xem có bao nhiêu hàng đã thực sự được sửa đổi. Nếu bạn sửa đổi chính xác một hàng, bạn biết hàng đó không thay đổi kể từ khi bạn đọc nó. Nếu bạn sửa đổi 0 hàng, bạn biết rằng hàng đó đã thay đổi và bạn có thể xử lý lỗi.
Vì vậy, ví dụ:bạn sẽ chọn dữ liệu cùng với số phiên bản
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
Khi bạn đã sẵn sàng cập nhật, bạn sẽ làm điều gì đó tương tự như thế này khi bạn sử dụng version
trong UPDATE
của bạn và thông báo lỗi nếu hàng đã thay đổi
UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
Ứng dụng của bạn sau đó sẽ làm điều gì đó hữu ích với lỗi. Thông thường, điều đó có nghĩa là thực hiện một số việc như truy vấn lại dữ liệu, trình bày các thay đổi cho người dùng và hỏi họ liệu họ có muốn áp dụng các thay đổi của mình hay không. Ví dụ:nếu tôi đọc một địa chỉ và bắt đầu chỉnh sửa nó, đi ăn trưa, đồng nghiệp của tôi đăng nhập, đọc cùng một địa chỉ, thực hiện một số chỉnh sửa và lưu nó, sau đó tôi quay lại và cố gắng lưu các thay đổi của mình, điều đó nói chung là hợp lý. để cho tôi xem điều gì đó cho tôi biết rằng đồng nghiệp của tôi đã thay đổi địa chỉ thành địa chỉ mới-- tôi muốn tiếp tục chỉnh sửa hay tôi muốn từ bỏ chúng.