2010-09-22 35 views
8

Tôi muốn khóa một bản ghi và sau đó không ai có thể thay đổi bản ghi đó. Khi tôi mở khóa, mọi người có thể thay đổi bản ghi.Làm cách nào để thực hiện khóa hàng?

Trong khi chờ một bản ghi bị khóa, tôi muốn hiển thị cho người dùng cảnh báo rằng bản ghi đã bị khóa và thay đổi đó không được phép.

Tôi làm cách nào để thực hiện việc này?

Tôi đã thử tất cả các cấp IsolationLevel, nhưng không ai trong số họ có hành vi mà tôi muốn. Một số mức cách ly chờ cho đến khi khóa được giải phóng và sau đó thực hiện thay đổi. Tôi không muốn điều này, bởi vì cập nhật không được cho phép tại thời điểm một bản ghi bị khóa.

Tôi có thể làm gì để khóa bản ghi và từ chối tất cả thay đổi?

Tôi sử dụng SQL Server 2008

+0

Tùy thuộc vào cơ sở dữ liệu. Cái nào? – pascal

+0

SQL Server 2008 – Martijn

Trả lời

0

Xem điều này duplicate question trên SO.

Về cơ bản đó là:

begin tran 

select * from [table] with(holdlock,rowlock) where id = @id 

--Here goes your stuff 

commit tran 

Lưu Trữ

Something như thế này có lẽ?

update t 
set t.IsLocked = 1 
from [table] t 
where t.id = @id 

Một nơi nào đó trong bản cập nhật kích hoạt:

if exists (
select top 1 1 
from deleted d 
join inserted i on i.id = d.id 
where d.IsLocked = 1 and i.RowVersion <> d.RowVersion) 
begin 
print 'Row is locked' 
rollback tran 
end 
+0

Tôi đã thử điều này, nhưng tôi vẫn có thể chọn dữ liệu và khi tôi thực hiện cập nhật, câu lệnh chờ cho đến khi khóa được giải phóng và sau đó thực hiện cập nhật. Đây không phải là điều tôi muốn. Tôi muốn thông báo cho người dùng nếu hồ sơ bị khóa. – Martijn

1

Sql Server đã khóa gợi ý, nhưng đây là những giới hạn trong phạm vi của một truy vấn.

Nếu quyết định khóa hồ sơ được thực hiện trong một ứng dụng, bạn có thể sử dụng các cơ chế tương tự như khóa lạc quan và từ chối mọi thay đổi đối với hồ sơ từ ứng dụng.

Sử dụng dấu thời gian hoặc guid làm khóa trên hồ sơ và từ chối truy cập hoặc thay đổi bản ghi nếu khóa khóa sai. Hãy cẩn thận để mở khóa hồ sơ một lần nữa hoặc bạn sẽ nhận được trẻ mồ côi

+1

Tôi đã nghĩ về cách tiếp cận như vậy, nhưng nếu ứng dụng bị treo thì sao? Hoặc nếu máy chủ bị hỏng. Làm cách nào để mở khóa bản ghi trong một tình huống như vậy? – Martijn

+0

Không có cách nào dễ dàng, tôi nghĩ vậy. Làm cho các khóa hết hạn bằng cách ghi lại một datetime rằng nó đã bị khóa và sử dụng một kích hoạt hoặc công việc theo lịch trình để làm sạch ổ khóa tồn tại quá lâu. Những gì bạn đang làm chủ yếu là khóa bi quan. cũng thấy điều này: http://stackoverflow.com/questions/386162/pessimistic-lock-in-t-sql – stombeur

9

Với giả thiết rằng đây là máy chủ MS SQL, bạn có thể muốn UPDLOCK, có thể kết hợp với ROWLOCK (Table hints). Tôi đang gặp khó khăn khi tìm một bài viết khá trong đó mô tả lý thuyết, nhưng ở đây là nhanh chóng dụ:

SELECT id From mytable WITH (ROWLOCK, UPDLOCK) WHERE id = 1 

Tuyên bố này sẽ đặt một update lock trên hàng trong suốt thời gian giao dịch (vì vậy điều quan trọng là phải nhận thức khi giao dịch kết thúc). Khi khóa cập nhật là incompatible with exclusive locks (yêu cầu cập nhật hồ sơ), điều này sẽ ngăn không cho bất kỳ ai cập nhật hồ sơ này cho đến khi giao dịch kết thúc.

Lưu ý rằng các quá trình khác cố gắng sửa đổi hồ sơ này sẽ bị chặn cho đến khi giao dịch kết thúc, tuy nhiên sẽ tiếp tục với bất kỳ thao tác ghi nào họ yêu cầu sau khi giao dịch kết thúc (trừ khi chúng hết hạn hoặc bị hủy bỏ như một quá trình bế tắc). Nếu bạn muốn ngăn chặn điều này thì các quá trình khác của bạn cần phải sử dụng các gợi ý bổ sung để hủy bỏ nếu một khóa không tương thích được phát hiện, hoặc bỏ qua bản ghi nếu nó đã thay đổi.


Ngoài ra, Bạn không nên sử dụng phương pháp này để khóa các hồ sơ trong khi chờ đợi cho người dùng nhập vào. Nếu đây là ý định của bạn thì bạn nên thêm một số cột "đang được sửa đổi" vào bảng của bạn để thay thế.

Cơ chế khóa máy chủ SQL thực sự chỉ phù hợp để sử dụng để bảo toàn toàn vẹn dữ liệu/ngăn ngừa khóa chết - các giao dịch thường được giữ càng ngắn càng tốt và chắc chắn không nên được duy trì trong khi chờ người dùng nhập.

+0

Khi tôi sử dụng câu lệnh cập nhật này cho đến khi khóa được giải phóng và sau đó thực hiện cập nhật. Tôi không muốn hành vi này. Ngay khi một bản ghi bị chặn, người dùng phải xem một tin nhắn. Làm theo cách này, tôi không thể thông báo cho người dùng vì câu lệnh cập nhật chờ cho đến khi khóa được giải phóng. Tôi muốn báo cáo cập nhật dừng lại và cho bằng cách nào đó một lỗi/ngoại lệ/cảnh báo để tôi có thể thông báo cho người dùng. – Martijn

+0

@Martijn - Câu lệnh cập nhật thứ hai của bạn cần phải được thực hiện với gợi ý 'NOWAIT', điều này sẽ khiến nó trở lại ngay sau khi khóa gặp phải thay vì đợi thời gian chờ. – Justin

+0

Không nên đọc câu lệnh 'SELECT id Từ mytable WITH (ROWLOCK, UPDLOCK) WHERE id = 1'? – nash

0

Bạn không muốn chờ khóa được phát hành và hiển thị thông báo ngay sau khi bạn gặp phải một khóa, nếu đây là trường hợp thì bạn đã thử NOWAIT. Xem Table Hints (Transact-SQL)SQL Server 2008 Table Hints để biết thêm chi tiết. Để có được lợi ích của NOWAIT, bạn cần phải khóa hồ sơ trên các chỉnh sửa, google để biết thêm chi tiết.

Các vấn đề liên quan