困惑于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行的能力。 这使您可以再次运行查询并查看相同的结果。