在事务中显示使用HOLDLOCK
或UPDLOCK
(例如T1),不会阻止来自另一个事务的读取访问(比如T2)。
据我了解,在T1完成之前,HOLDLOCK
将阻止T2更新/删除;并且UPDLOCK
将阻止T2更新/删除/插入。在这两个T2中都有对这些记录的读访问权。
但是,使用两者(例如:HOLDLOCK, UPDLOCK
)即使是读取访问也会阻止T2。当我们同时使用它们时究竟会发生什么?
感谢您的见解
这不是我所看到的:
例如:
在查询1中:
begin tran
select * from tblTest WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10'
commit tran
在查询2中:
select * from tblTest
在查询1完成之前,查询2不会产生结果。
答案 0 :(得分:11)
UPDLOCK
会影响锁定类型。这意味着SELECT
语句将采用U
锁而不是S
锁。在默认的读取提交级别,它们将在读取数据后立即释放。
以上内容适用于行和页锁。对于表级锁定BOL状态
如果UPDLOCK与TABLOCK结合使用,或者采用表级锁定 由于某些其他原因,将采用独占(X)锁定。
HOLDLOCK
表示您获得了可序列化的隔离语义,因此在事务结束之前锁定不会被释放,并且至少会锁定查询所涵盖的整个范围以防止插入幻像。
U
锁与其他S
锁兼容,但不与其他U
锁兼容(请参阅Lock compatibility matrix),因此如果锁在行或页面级别取出除非他们也使用UPDLOCK
提示,否则不会阻止其他读者。
如果由于X
导致对象级UPDLOCK
锁定被取消,则会阻止读者 尝试获取表格上的IS
锁定。在您的示例查询中,请尝试查看sys.dm_tran_locks
,同时阻止第二个查询以查看两个事务已等待/正在等待的锁定。
对于您问题中的查询
SELECT *
FROM tblTest WITH (UPDLOCK, HOLDLOCK)
如果查询计划在堆上显示扫描,您将始终在对象上获得X
锁定。如果是索引扫描,则取决于所使用的锁定粒度(通常在执行at least 5,000次级锁定后尝试锁定升级到表级别)。
答案 1 :(得分:4)
我相信马丁已经解释了updlock
如何导致排他锁定(+1)......我宁愿将其发布为评论/问题,但我的评论太大了...... / p>
以下是导致updlock
锁定的x
的简单示例...
IF (OBJECT_ID('tblTest') IS NOT NULL)
DROP TABLE tblTest
CREATE TABLE tblTest (
ID INT NOT NULL
)
BEGIN TRANSACTION
SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID
COMMIT
但是,如果向表中添加聚簇索引,则独占表锁将消失,并替换为RangeS-U
锁...
ALTER TABLE dbo.tblTest
ADD CONSTRAINT PK_tblTest
PRIMARY KEY CLUSTERED (ID)
BEGIN TRANSACTION
SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID
COMMIT
所以基本上,你在这张桌子上有聚集索引吗?
编辑:
使用非聚集索引的另一个例子......
IF (OBJECT_ID('tblTest') IS NOT NULL)
DROP TABLE tblTest
CREATE TABLE tblTest (
ID INT NOT NULL
)
CREATE NONCLUSTERED INDEX
IX_tblTest ON dbo.tblTest (ID)
BEGIN TRANSACTION
SELECT * FROM dbo.tblTest WITH (HOLDLOCK) WHERE ID = 1
SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID
COMMIT
会导致RangeS-S
锁定...
但是...
BEGIN TRANSACTION
SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID
COMMIT
会导致独占表锁...
答案 2 :(得分:1)
如果表没有适当的查询索引,则可序列化隔离会导致执行表锁定。 HOLDLOCK使serializable成为上面提到的表的有效事务隔离级别。
这与其他人提到的X
升级一起导致您看到的行为。