Azure SQL DB 并发事务处理及行级锁识别实现问题咨询
问题解答
第2点:实现其他会话可更新非锁定行的方案
你遇到的其他行无法更新的问题,不是表上的IX意向锁导致的,IX锁只会阻塞对整个表的共享/排他锁,不会阻塞其他行的更新操作。根因是你加UPDLOCK的SELECT语句触发了全表/全索引扫描,扫描过程中会给所有途经的行加U锁,即便加了ROWLOCK提示也无效。
解决步骤如下:
- 确保表有主键(默认创建聚集索引),加UPDLOCK的SELECT语句必须用主键等值作为WHERE条件,或者用到唯一非聚集索引的等值匹配,保证执行计划是**索引查找(Seek)**而非扫描。此时只会给目标行加U锁,完全不影响其他行的更新。
示例加锁语句:BEGIN TRANSACTION; -- 必须保证WHERE后的主键匹配能走到索引查找 SELECT * FROM 你的表名 WITH (UPDLOCK, ROWLOCK) WHERE 主键列 = 目标主键值; -- 此处写后续的更新业务逻辑 COMMIT TRANSACTION; - 不需要加READPAST提示,该提示会让查询跳过已加锁的行,可能导致你无法获取到目标行的锁。
- 如果确认执行计划是索引查找仍出现锁阻塞,可手动关闭目标表的锁升级:
ALTER TABLE 你的表名 SET (LOCK_ESCALATION = DISABLE);,Azure SQL DB基本层数据量普遍不大,锁升级概率很低,该操作仅作为兜底方案。
第3点:行级锁与主键、锁定用户的匹配方案
该需求可以实现,借助SQL Server内置的%%lockres%%虚拟列即可关联行锁资源和实际行数据,具体查询逻辑如下:
-- 提前替换SQL中的占位符:你的表名、主键列名 SELECT s.session_id AS 会话ID, s.login_name AS 锁定用户账号, t.resource_description AS 行锁资源标识, d.主键列名 AS 被锁行主键值 FROM sys.dm_tran_locks t INNER JOIN sys.dm_exec_sessions s ON t.request_session_id = s.session_id INNER JOIN sys.objects o ON t.resource_associated_entity_id = o.object_id CROSS APPLY ( SELECT 主键列名 FROM 你的表名 WHERE %%lockres%% = t.resource_description ) d WHERE o.name = '你的表名' -- 堆表用resource_type = 'RID',聚集索引表用resource_type = 'KEY' AND t.resource_type = 'KEY' AND t.request_mode IN ('U', 'X') AND t.request_status = 'GRANT';
注意事项:
- 大表查询时可先过滤出目标表的行锁资源列表,再单独查询每行的主键值,避免全表扫描产生性能开销。
第1点确认
你当前用UPDLOCK实现其他用户可读的方案是正确的,因为RCSI(读提交快照隔离)级别下,读操作不会请求共享锁,直接读取行版本数据,完全不会被U/X锁阻塞,符合你的需求。
内容的提问来源于stack exchange,提问作者Iniyavan
相关产品推荐
相关产品推荐

