我有一个简单的getNextID过程,用于检索表中的id值并将该值递增1.它是在考虑到一些多线程的情况下构建的,但似乎UPDLOCK在该程序实际上并没有像预期的那样使线程安全,我试图理解为什么。这个想法是,初始选择期间的UPDLOCK会阻止任何其他线程执行该选择,直到该过程底部的更新完成;然而,这似乎并不是这种情况,因为当两个线程同时触发时,我得到重复值。T-SQL函数在UPDLOCK之后不是线程安全的
阅读一些其他线程之后,我认为可能发生的是UPDLOCK阻止其他线程更新行,但不阻止他们更新之前执行初始选择。因此,两个线程都执行相同的select(检索相同的值),则线程2正在等待线程1更新,然后线程2将该行更新为相同的值。我理解锁正在做什么?实现线程验证的正确方法是将它全部包装在BEGIN/COMMIT TRANSACTION中吗?
CREATE PROCEDURE getNextID (
@NextNumber int OUTPUT
,@id_type VARCHAR(20)
)
AS
BEGIN
SELECT @NextNumber = (last_used_number + 1)
FROM its_id_sequence WITH (UPDLOCK)
WHERE id_type = @id_type
UPDATE its_id_sequence
SET last_used_number = @NextNumber
WHERE id_type = @id_type
END
谢谢!
无论何时你试图推出自己的身份,你都在为一场失败的战斗而战。围绕这一点有很多挑战。为什么不使用已经完全实用的身份属性?如果你不喜欢差距(当然这是完全正常的),如果你在2012+以上,你可以改用序列。 –
@SeanLange:我认为一个序列不能保证无间隙。 _Maybe_如果您在创建序列时指定了“no cache”,但会影响性能。我从来没有任何人能够合理地解释序列中没有空白的业务需求。 –
@BenThul序列本身是无缝的。但是,如果您将它用作主键,只要删除一行,它就会以间隙结束。 OP在这里所做的基本上与已经构建的序列是一样的。 –