对UPDLOCK,HOLDLOCK感到困惑

Jef*_*ata 85 t-sql sql-server concurrency locking sql-server-2008

在研究Table Hints的使用时,我遇到了这两个问题:

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

测试表:

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]
Run Code Online (Sandbox Code Playgroud)

从SSMS窗口1:

BEGIN TRANSACTION

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

COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)

从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'
Run Code Online (Sandbox Code Playgroud)

不同表提示对窗口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
Run Code Online (Sandbox Code Playgroud)

我是否误解了这些问题中给出的答案,或者在我的测试中犯了错误?如果没有,你为什么要使用(UPDLOCK, HOLDLOCK)(HOLDLOCK)一个人吗?


进一步解释我想要完成的事情:

我想从表中选择行,并防止在处理该表时修改该表中的数据.我没有修改那些数据,并希望允许读取.

这个答案明确表示(UPDLOCK, HOLDLOCK)会阻止读取(不是我想要的).对这个答案的评论意味着它会HOLDLOCK阻止读取.为了更好地理解表格提示的效果,看看是否UPDLOCK单独做了我想做的事情,我做了上述实验并得到了与这些答案相矛盾的结果.

目前,我认为这(HOLDLOCK)是我应该使用的,但我担心我可能犯了一个错误或忽略了将来会再次咬我的东西,因此这个问题.

Rem*_*anu 95

为什么UPDLOCK会选择?该锁兼容性矩阵清楚地表明N了S/U和U/S争,在没有冲突.

至于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无需解释

真正的问题是你想要实现的目标什么?玩锁定提示没有绝对完全110%的锁定语义理解是乞求麻烦...

OP编辑后:

我想从表中选择行,并防止在处理该表时修改该表中的数据.

您应该使用较高的事务隔离级别之一.REPEATABLE READ将阻止您读取的数据被修改.SERIALIZABLE将阻止您读取的数据被修改插入新数据.与使用查询提示相反,使用事务隔离级别是正确的方法.Kendra Little有一张漂亮的海报,散发着隔离层次.


Sco*_*uns 20

如果要在select语句期间为将来的更新语句锁定一行或多行,则使用UPDLOCK.未来的更新可能是事务中的下一个语句.

其他会话仍然可以看到数据.他们只是无法获得与UPDLOCK和/或HOLDLOCK不兼容的锁.

当您想要阻止其他会话更改已锁定的行时,可以使用UPDLOCK.它限制了他们更新或删除锁定行的能力.

如果要阻止其他会话更改您正在查看的任何数据,请使用HOLDLOCK.它限制了它们插入,更新或删除已锁定行的能力.这允许您再次运行查询并查看相同的结果.

  • 谢谢,但我认为您没有真正回答我的问题:这些问题的答案是否错误地说明“(UPDLOCK,HOLDLOCK)”块读取,以及是否有理由使用“(UPDLOCK,HOLDLOCK)” ` 而不是只是 `(HOLDLOCK)`? (2认同)