我正在编写一个T-SQL存储过程,只有当类似记录的数量低于某个阈值时才会有条件地将记录添加到表中,如下例所示。问题是这将从Web应用程序运行,因此它将在多个线程上运行,我需要确保该表永远不会有超过10个类似的记录。
该程序的基本要点是:
BEGIN
DECLARE @c INT
SELECT @c = count(*)
FROM foo
WHERE bar = @a_param
IF @c < 10 THEN
INSERT INTO foo
(bar)
VALUES (@a_param)
END IF
END
我认为我可以通过将select语句替换为:
来解决任何潜在的并发问题SELECT @c = count(*) WITH (TABLOCKX, HOLDLOCK)
但我很好奇是否有其他方法除了用于管理T-SQL中的并发问题的锁定提示
答案 0 :(得分:1)
使用SERIALIZABLE
。根据定义,它为您提供了一个错觉,即您的事务是唯一运行的事务。请注意,这可能会导致阻塞和死锁。事实上,这个SQL代码是死锁的经典候选:两个事务可能首先读取一组行,然后两个都会尝试修改这组行。锁定提示是解决该问题的经典方法。重试也有效。
答案 1 :(得分:1)
一种选择是使用sp_getapplock系统存储过程。您可以将关键部分逻辑放在事务中,并使用sql server的内置锁定来确保同步访问。
示例:
CREATE PROC MyCriticalWork(@MyParam INT)
AS
DECLARE @LockRequestResult INT
SET @LockRequestResult=0
DECLARE @MyTimeoutMiliseconds INT
SET @MyTimeoutMiliseconds=5000--Wait only five seconds max then timeouit
BEGIN TRAN
EXEC @LockRequestResult=SP_GETAPPLOCK 'MyCriticalWork','Exclusive','Transaction',@MyTimeoutMiliseconds
IF(@LockRequestResult>=0)BEGIN
/*
DO YOUR CRITICAL READS AND WRITES HERE
*/
--Release the lock
COMMIT TRAN
END ELSE
ROLLBACK TRAN
答案 2 :(得分:0)
如评论中所述。为什么要尝试在多个线程上插入?您无法在多个线程上更快地写入表。
但你不需要声明
insert into [Table_1] (ID, fname, lname)
select 3, 'fname', 'lname'
from [Table_1]
where ID = 3
having COUNT(*) <= 10
如果您需要锁定,请执行此操作