SQL Server分布式锁查询:如何判断指定名称的分布式锁是否存在
SQL Server分布式锁存在性查询方案
原有方案合理性说明
你总结的判断逻辑仅在排他锁测试场景下可得到正确结果,但存在明显局限性:
APPLOCK_MODE仅能返回当前会话持有的目标锁模式,其他会话持有的锁无法通过该函数感知,当其他会话持有共享锁等非排他锁时,你的判断逻辑会出现误判- 逻辑耦合当前会话状态,无法独立查询任意会话持有的分布式锁
不受当前连接限制的通用查询方案
方案1:查询系统动态视图(无副作用,优先推荐)
通过全局动态视图sys.dm_tran_locks可直接查询所有会话持有的应用锁,无需修改锁状态:
DECLARE @TargetLockName SYSNAME = 'testlock' -- 替换为你要查询的锁名称 DECLARE @TargetDB SYSNAME = DB_NAME() -- 锁所属数据库,默认取当前数据库可手动修改 SELECT CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END AS is_lock_exist FROM sys.dm_tran_locks WHERE resource_type = 'APPLICATION' -- 应用程序锁标识 AND DB_NAME(resource_database_id) = @TargetDB AND RESOURCE_NAME = CONVERT(VARCHAR(64), HASHBYTES('SHA2_256', @TargetLockName), 2)
注意:该方案需要查询账号拥有
VIEW SERVER STATE权限。
方案2:零超时尝试加锁(无权限要求)
如果没有系统视图查询权限,可以通过设置0超时尝试加锁的方式判断,不会造成会话堵塞:
DECLARE @LockResult INT DECLARE @TargetLockName SYSNAME = 'testlock' -- 尝试获取排他锁,超时时间设为0,不等待 EXEC @LockResult = sp_getapplock @Resource = @TargetLockName, @LockMode = 'Exclusive', @LockOwner = 'Session', @LockTimeout = 0, @DbPrincipal = 'public' IF @LockResult >= 0 BEGIN -- 成功获取锁,说明无其他会话持有,立即释放避免占用 EXEC sp_releaseapplock @Resource = @TargetLockName, @LockOwner = 'Session', @DbPrincipal = 'public' SELECT 0 AS is_lock_exist END ELSE BEGIN -- 获取失败,锁已被其他会话持有 SELECT 1 AS is_lock_exist END
若需要判断是否存在任意模式的锁,可将
@LockMode调整为对应的锁模式参数即可。
内容的提问来源于stack exchange,提问作者Seabizkit
相关产品推荐
相关产品推荐

