【发布时间】:2016-01-08 14:29:32
【问题描述】:
根据UPDATE documentation,UPDATE 总是在整个表上获得排他锁。但是,我想知道是在确定要更新的行之前获得独占锁还是仅在实际更新之前获得。
我的具体问题是我的SELECT 中有一个嵌套的UPDATE,如下所示:
UPDATE Tasks
SET Status = 'Active'
WHERE Id = (SELECT TOP 1 Id
FROM Tasks
WHERE Type = 1
AND (SELECT COUNT(*)
FROM Tasks
WHERE Status = 'Active') = 0
ORDER BY Id)
现在我想知道是否真的可以保证只有一个
如果并行执行相同的语句,则可以使用另一个类型执行Status = 'Active' 的任务:
UPDATE Tasks
SET Status = 'Active'
WHERE Id = (SELECT TOP 1 Id
FROM Tasks
WHERE Type = 2 -- <== The only difference
AND (SELECT COUNT(*)
FROM Tasks
WHERE Status = 'Active') = 0
ORDER BY Id)
如果对于这两个语句,要更改的行将在获取锁之前确定,我可能会得到两个我必须阻止的活动任务。
如果是这种情况,我该如何预防?我可以在不将事务级别设置为SERIALIZABLE 或使用锁定提示的情况下阻止它吗?
从Is a single SQL Server statement atomic and consistent? 的回答中,我了解到当嵌套的SELECT 访问另一个表时会出现问题。但是,如果只关注更新的表,我不确定是否需要关心这个问题。
【问题讨论】:
-
该文档无论如何都是错误的。更新通常不会锁定整个表。
-
嗯,好的,谢谢。但是我在哪里可以找到正确的文档呢?
-
文档实际上并没有说
UPDATE锁定了整个表。它说它获得了一个排他锁,但排他锁不必在整个表上。 -
如果您锁定整个数据库,您的并发性就会受到限制,因此现代数据库会尝试仅锁定正在修改的记录。至少在可能的情况下。当然,这取决于数据库、查询和版本。无论如何,这似乎不是最强大的锁定机制。这可能会导致难以重现或调试的错误。
-
我只是想锁定表,而不是整个数据库。我正在做的事情很少发生,所以阻碍并发不是问题。我只需要确定一条记录将被设置为活动状态。
标签: sql sql-server transaction-isolation