BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else
在我看来,这样做并不能正确地处理并发。仅仅因为你有一个事务,并不意味着在你执行更新语句之前,其他人不会读取相同的值。
现在,将代码保持不变(我意识到最好使用单个语句或者更好地使用自增/标识列),有哪些确保它能正确处理并发并防止出现允许两个客户端获取相同id值的竞争条件的方法?
我很确定在SELECT语句中添加WITH (UPDLOCK, HOLDLOCK)可以解决问题。可串行化事务隔离级别似乎也可以工作,因为它拒绝其他人在事务结束之前读取你所读取的内容(更新:这是错误的,请参考Martin的回答)。这是真的吗?它们都能很好地工作吗?有没有一种更优选的方法?
想象一下,做一些比更新ID更合理的操作——基于读取的计算需要进行更新。可能涉及到多个表,其中一些你会写入,而其他一些则不会。在这种情况下,最佳实践是什么?
写完这个问题后,我觉得锁提示更好,因为这样你只会锁定你需要的表,但我很感谢任何人的意见。
顺便说一句,不,我不知道最佳答案,真的想要更好地理解! :)