我以为我理解了SQL的锁定机制,但似乎我没有。我知道你可以拥有共享和独占锁,并且可以同时在同一数据上应用2个共享锁。但有人可以解释为什么查询1不会阻止查询2.我希望serializable关键字将给我一个独占锁而不是共享锁。要具体:
我创建了一个用户表:
我打开用user1连接到该数据库的sql management studio并执行以下查询:
BEGIN TRAN
select * from [user] WITH(SERIALIZABLE, TABLOCK, HOLDLOCK)
我故意保持交易开放。
比我打开第二个sql mangement studio用user2连接到同一个数据库并执行相同的查询。我预计第二个查询会继续运行,因为查询1在表上保持锁定,但它没有。第二个查询直接执行。为什么是这样?我的锁定提示被忽略了吗?
答案 0 :(得分:1)
SERIALIZABLE = HOLDLOCK
制作共享锁TABLOCK
指定在表级应用获取的锁。 (SERIALIZABLE, TABLOCK)
=表上的共享(S)锁
如果需要使用Exclusive(X)锁定
TABLOCKX
或(TABLOCK,UPDLOCK)
或(TABLOCK,XLOCK)
答案 1 :(得分:1)
首先,on this thread很好地解释了SELECT
语句无法阻止另一个语句,因为两者都只获取资源上的Shared (S)
锁定,这意味着该行可用于读。阅读所有锁类型的更多here。
但是,您试图通过使用Exclusive (X)
提示强制select语句获取WITH(SERIALIZABLE, TABLOCK, HOLDLOCK)
锁定。
这些提示"仅适用于您正在使用它的表或视图,并且仅适用于在" 中使用它们的语句定义的事务的持续时间。这在documentation中说明。
SERIALIZABLE
提示通过在事务完成之前保留共享锁来限制共享锁,而不是在不再需要数据时立即释放锁。但请记住,它仍然是共享锁。
为了强制执行独占锁定,您可以执行以下操作:
SELECT *
FROM YourTable WITH (XLOCK, ROWLOCK)
SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'
第二个查询将为您提供有关此语句中所有获取的锁的信息。 通过在某些表格中选择,我得到了以下结果:
请注意,我们在Intent shared (IX)
和PAGE
本身上有一个OBJECT
锁定,这是我们选择的表格,每个键上都有一个Exclusive (X)
锁定