2009-01-30 29 views
16

Tôi muốn thực hiện một giao dịch nguyên tử như sau:Tôi nên sử dụng gợi ý khóa nào (T-SQL)?

BEGIN TRAN A 

SELECT id 
FROM Inventory 
WITH (???) 
WHERE material_id = 25 AND quantity > 10 

/* 
Process some things using the inventory record and 
eventually write some updates that are dependent on the fact that 
that specific inventory record had sufficient quantity (greater than 10). 
*/ 

COMMIT TRAN A 

Vấn đề là có những giao dịch khác xảy ra mà tiêu thụ số lượng từ hàng tồn kho của chúng tôi, vì vậy giữa thời điểm mà các hồ sơ được chọn và các bản cập nhật được viết trong giao dịch Một bản ghi đó có thể trở thành lựa chọn không hợp lệ vì số lượng của nó có thể đã được hạ xuống dưới ngưỡng trong mệnh đề WHERE. Vì vậy, câu hỏi là những gợi ý khóa nào tôi nên sử dụng trong mệnh đề WITH để ngăn không cho bản ghi kiểm kê đã chọn bị thay đổi trước khi tôi hoàn tất các cập nhật của mình và cam kết giao dịch?

EDIT: Vì vậy, cảm ơn John, một giải pháp tốt có vẻ là đặt mức cô lập giao dịch thành REPEATABLE READ. Điều này sẽ đảm bảo rằng "không có giao dịch nào khác có thể sửa đổi dữ liệu đã được giao dịch hiện tại đọc cho đến khi giao dịch hiện tại hoàn tất".

+0

Tốt câu hỏi ... Tôi sẽ được làm việc trên một số mã phù hợp chính xác tiêu chí này sớm ... Tôi thậm chí đã không nhận ra đó là một vấn đề :) –

+0

Cảm ơn Andrew! Yea nó xảy ra với tôi rằng một giao dịch không thực sự tạo ra một kết quả phù hợp nếu dữ liệu hoặc đúng hơn là các giả định giao dịch đang sử dụng được thay đổi trong khi nó đang xử lý. – Daniel

Trả lời

11

Bạn thực sự có thể được tốt hơn thiết lập mức cô lập giao dịch hơn là sử dụng một gợi ý truy vấn.

Tham chiếu sau đây từ Sách trực tuyến cung cấp chi tiết về từng mức cách ly khác nhau.

http://msdn.microsoft.com/en-us/library/ms173763.aspx

Dưới đây là bài viết tốt mà giải thích các loại khóa hành vi trong SQL Server và cung cấp ví dụ quá.

http://www.sqlteam.com/article/introduction-to-locking-in-sql-server

+0

Vì vậy, sau đó bạn sẽ đề nghị sử dụng mức độ cô lập REPEATABLE READ? – Daniel

+0

Có điều này chắc chắn sẽ hoạt động. Để tham khảo trong tương lai, bạn có thể muốn tự học về các mức cô lập khác có sẵn trong SQL Server, sử dụng phiên bản hàng. Đây là một kiến ​​thức khá khó đọc nhưng có giá trị, http://msdn.microsoft.com/en-us/library/ms345124.aspx –

+0

Câu trả lời hay - chúng tôi đã xem xét tất cả các tài liệu mức cô lập khi thiết lập DB StackOverflow của chúng tôi. –

0

Tôi tin rằng đây sẽ là UPDLOCK.

http://www.devx.com/tips/Tip/13134

+0

Hãy nhớ rằng khóa không cư xử theo cách này trong SQL Server 2005 trở lên. Bài viết này khá rõ ràng. –

+0

Tôi đang sử dụng SQL Server 2005. – Daniel

0

VỚI UPDLOCK, HOLDLOCK

+1

Tại sao HOLDLOCK lại cần thiết? – Daniel

+1

để đảm bảo rằng không có quá trình nào khác có thể đọc được điều này và nó sẽ giữ nó trong suốt thời gian của tran – SQLMenace

+1

UPDLOCK đạt được rằng – gbn

2

table hints

WITH (HOLDLOCK) cho phép độc giả khác. UPDLOCK như được đề xuất ở nơi khác là độc quyền.

HOLDLOCK sẽ ngăn các cập nhật khác nhưng chúng có thể sử dụng dữ liệu được cập nhật sau.

UPDLOCK sẽ ngăn mọi người đọc dữ liệu cho đến khi bạn cam kết hoặc khôi phục.

Bạn đã xem sp_getapplock chưa? Điều này sẽ cho phép bạn nối tiếp mã này (nếu đó là bit cập nhật duy nhất) mà không cần UPDLOCK chặn

Chỉnh sửa: Vấn đề nằm chủ yếu trong mã này chạy trong 2 phiên khác nhau. Với HOLDLOCk hoặc REPEATABLE_READ, dữ liệu sẽ được đọc trong phiên thứ 2 trước khi cập nhật phiên đầu tiên. Với UPDLOCK, không ai có thể đọc dữ liệu trong bất kỳ phiên nào.

+0

Vấn đề không cố gắng giữ cho Seesion B đọc dữ liệu trong khi Phiên A đang thực hiện giao dịch. Vấn đề là giữ cho phiên B không được ghi vào hàng mà giao dịch của phiên A đang sử dụng trong các phép tính của nó, để ngăn các tính toán sử dụng dữ liệu cũ. – Daniel

+0

bẻ khóa rồi. Cho phép đọc nhưng không viết. Hoặc tải tất cả dữ liệu vào các biến vars/bảng cục bộ – gbn

2

MSSQL:

SELECT id 
FROM Inventory (UPDLOCK) 
WHERE material_id = 25 AND quantity > 10; 

http://www.devx.com/tips/Tip/13134 



Bởi cơ hội nào bạn quan tâm với PostgreSQL:

SELECT id 
FROM Inventory  
WHERE material_id = 25 AND quantity > 10 
FOR UPDATE; 
Các vấn đề liên quan