SQLServer 为什么 SELECT WITH(XLOCK)
锁住记录之后仍然可以被别的事务查询出来?
🏷️ SQL Server
WITH(XLOCK)
是排它锁,别的事务中的查询应该被阻塞才对啊?
现象
在事务 1 中使用
SELECT WITH(XLOCK)
锁定某一条语句;在事务 2 中仍然可以查询到该语句,不会被阻塞;
在事务 1 中更新该记录;
在事务 2 中查询该记录会被阻塞;
问题
查询系统表,1 中确实给数据加了 X 锁;
sql
SELECT request_session_id, resource_type,
request_status, request_mode,
resource_description, object_name(p.object_id) as object_name,p.index_id
FROM sys.dm_tran_locks left join sys.partitions p
on sys.dm_tran_locks.resource_associated_entity_id = p.hobt_id
因为是排它锁,2 中的查询应该被阻塞才对,但是能被正常查询到,没被阻塞 (貌似有些表或者有些时候又会被阻塞);
3 和 4 的执行结果倒是跟预想一样,数据被修改后,阻塞别的事务中的对该条记录的查询,完全符合排它锁的特征。
改为使用 WITH(READPAST, XLOCK)
来判断该记录是否被锁定;
通过下图可以看出,使用 WITH(READPAST, XLOCK)
的加锁情况是跟 WITH(XLOCK)
一致的;
当该条记录已经被加锁时,再使用 WITH(READPAST, XLOCK)
去取就会忽略该条记录,不会堵塞查询。
这样就可以用来判定该记录是否已被加锁,若加锁则可以中断业务处理,而不是等待。
付上一张各种锁的冲突关系图