对UPDLOCK,HOLDLOCK感到困惑

时间:2011-10-21 00:12:53

标签: sql-server tsql sql-server-2008 concurrency locking

在研究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]

从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

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


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

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

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

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

2 个答案:

答案 0 :(得分:89)

为什么UPDLOCK会选择? Lock Compatibility Matrix清楚地显示了{/ 1}}的S / U和U / S争用,如 No Conflict

至于HOLDLOCK提示文档说明:

  

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

     

...

     

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

Transaction Isolation Level主题解释了SERIALIZABLE的含义:

  

没有其他事务可以修改已被读取的数据   当前事务完成之前的当前事务。

     

其他事务无法插入具有键值的新行   落在当前任何语句读取的键范围内   交易直到当前交易完成。

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

  • UPDLOCK不阻止并发SELECT或INSERT,但阻止T1选择的行的任何UPDATE或DELETE
  • HOLDLOCK表示SERALIZABLE,因此允许SELECTS,但阻止T1,选择的行的UPDATE和DELETES以及作为T1选择的范围内的任何INSERT(这是整个表,因此< em> any insert)。
  • (UPDLOCK,HOLDLOCK):除了上面的情况,你的实验没有显示会阻止什么,即在T2中使用UPDLOCK的另一个事务
    N
  • TABLOCKX无需解释

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

OP编辑后:

  

我想从表中选择行并阻止其中的数据   在我处理它时,表格被修改。

您应该使用较高的事务隔离级别之一。 REPEATABLE READ将阻止您读取的数据被修改。 SERIALIZABLE将阻止您读取的数据被修改插入新数据。与使用查询提示相反,使用事务隔离级别是正确的方法。 Kendra Little有a nice poster exlaining the isolation levels

答案 1 :(得分:19)

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

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

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

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

相关问题