困惑于UPDLOCK,HOLDLOCK

在研究使用表格提示时 ,我遇到了这两个问题:

  • 我应该使用哪些locking提示(T-SQL)?

  • HOLDLOCK对UPDLOCK有什么影响?

两个问题的答案都表示,当使用(UPDLOCK, HOLDLOCK) ,其他进程将无法读取该表上的数据,但是我没有看到这一点。 为了testing,我创build了一个表,并启动了两个SSMS窗口。 从第一个窗口中,我使用各种表提示从表中select了一个事务。 当事务正在运行时,从第二个窗口我跑了各种语句,看看哪个会被阻塞。

testing表:

 CREATE TABLE [dbo].[Test]( [ID] [int] IDENTITY(1,1) NOT NULL, [Value] [nvarchar](50) NULL, CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] 

从SSMS窗口1:

 BEGIN TRANSACTION SELECT * FROM dbo.Test WITH (UPDLOCK, HOLDLOCK) WAITFOR DELAY '00:00:10' COMMIT TRANSACTION 

从SSMS窗口2(运行以下任一项):

 SELECT * FROM dbo.Test INSERT dbo.Test(Value) VALUES ('bar') UPDATE dbo.Test SET Value = 'baz' WHERE Value = 'bar' DELETE dbo.Test WHERE Value= 'baz' 

不同的表格提示对窗口2中运行的语句的影响:

  (UPDLOCK) (HOLDLOCK) (UPDLOCK, HOLDLOCK) (TABLOCKX) --------------------------------------------------------------------------- SELECT not blocked not blocked not blocked blocked INSERT not blocked blocked blocked blocked UPDATE blocked blocked blocked blocked DELETE blocked blocked blocked blocked 

我误解了这些问题中的答案,还是在testing中犯了错误? 如果不是,你为什么要单独使用(UPDLOCK, HOLDLOCK)(HOLDLOCK)


进一步解释我正在努力完成的事情:

我想从表中select行,并防止在处理表中的数据时被修改。 我不修改该数据,并希望允许读取发生。

这个答案清楚地表明(UPDLOCK, HOLDLOCK)会阻止读取(不是我想要的)。 这个答案的意见意味着它是HOLDLOCK ,防止读取。 为了更好地理解表格提示的效果,看看UPDLOCK是否能做我想做的事情,我做了上面的实验,得到了与这些答案相矛盾的结果。

目前,我认为(HOLDLOCK)是我应该使用的,但是我担心我可能犯了一个错误,或者忽略了一些将来会反弹的东西,所以就是这个问题。

为什么UPDLOCK块会select? 锁兼容性matrix清楚地显示了S / U和U / S争用的N ,如同没有冲突一样

至于HOLDLOCK提示文件指出:

HOLDLOCK:相当于SERIALIZABLE。 有关更多信息,请参阅本主题后面的SERIALIZABLE。

SERIALIZABLE:…使用与在SERIALIZABLE隔离级别上运行的事务相同的语义执行扫描…

事务隔离级别“主题解释了SERIALIZABLE意味着什么:

没有其他事务可以修改当前事务读取的数据,直到当前事务完成。

其他事务不能插入具有键值的新行,这些键值落在当前事务中任何语句读取的键的范围内,直到当前事务完成。

因此,您所看到的行为完全可以通过产品文档来解释:

  • UPDLOCK不会阻止并发的SELECT和INSERT,但会阻止T1所选行的任何UPDATE或DELETE
  • HOLDLOCK意味着SERALIZABLE,因此允许SELECTS,但是阻止T1所选行的UPDATE和DELETES, 以及 T1所选范围(即整个表,因此任何插入)中的任何 INSERT。
  • (UPDLOCK,HOLDLOCK):您的实验不会显示除上述情况外还会阻塞什么,即在T2中使用UPDLOCK进行另一个事务
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKX不需要解释

真正的问题是你想达到什么目的 ? 玩locking提示没有一个绝对完整的110%理解locking语义是乞求麻烦…

OP编辑后:

我想从表中select行,并防止在处理表中的数据时被修改。

您应该使用较高的事务隔离级别之一。 REPEATABLE READ将防止您读取的数据被修改。 SERIALIZABLE将防止您读取的数据被修改插入新的数据。 使用事务隔离级别是正确的方法,而不是使用查询提示。 肯德拉小有一个很好的海报,隔离级别 。

当你希望在select语句期间locking一行或多行以用于将来的更新语句时,使用UPDLOCK。 未来的更新可能是交易中的下一个陈述。

其他会话仍然可以看到数据。 他们不能获得与UPDLOCK和/或HOLDLOCK不兼容的锁。

当你想避免其他会话改变你locking的行时,你可以使用UPDLOCK。 它限制了他们更新或删除locking行的能力。

当您想让其他会话不会更改您正在查看的任何数据时,可以使用HOLDLOCK。 它限制了他们插入,更新或删除已locking行的能力。 这使您可以再次运行查询并查看相同的结果。