【发布时间】:2013-04-30 11:26:21
【问题描述】:
我有一个任意的存储过程usp_DoubleCheckLockInsert,它为多个客户端执行INSERT,当它位于临界区Begin lock 和End lock.
CREATE PROCEDURE usp_DoubleCheckLockInsert
@Id INT
,@SomeValue INT
AS
BEGIN
IF (EXISTS(SELECT 1 FROM SomeTable WHERE Id = @Id AND SomeValue = @SomeValue)) RETURN
BEGIN TRAN
--Begin lock
IF (EXISTS(SELECT 1 FROM SomeTable WHERE Id = @Id AND SomeValue = @SomeValue)) ROLLBACK
INSERT INTO SomeTable(Id, SomeValue)
VALUES(@Id,@SomeValue);
--End lock
COMMIT
END
我已经看到隔离级别与更新的关系,但是有没有办法在关键部分实现锁定,给事务写锁,或者 TSQL 不是这样工作的?
Obtain Update Table Lock at start of Stored Procedure in SQL Server
【问题讨论】:
-
为什么不在
Id, SomeValue上创建一个唯一约束?见Only inserting a row if it's not already there -
这是在数据级别解决问题的一种方法,但在我的情况下,某些记录有一个名为
IsDelete的软删除标志,因此相同Id和SomeValue的多个记录是允许的。 -
您可以使用唯一的过滤索引来强制执行此操作。
CREATE UNIQUE INDEX IX ON SomeTable(Id,SomeValue) WHERE IsDelete = 0 -
如果这是用户可以访问此表的唯一方式,您可能需要查看 sp_getapplock msdn.microsoft.com/en-us/library/ms189823.aspx
-
"这真的比双重检查锁定更可取吗?" - 是的,是的。在您经历了所有的扭曲之后,SQL Server 仍将应用所有其正常的锁定机制。在这种情况下,捕获错误是首选的工作方式。
标签: sql sql-server-2008 stored-procedures concurrency locking