如何在SQL Server中重现LCK_M_IX锁?解析其产生原因与本质
如何重现SQL Server的LCK_M_IX锁及锁的本质分析
一、LCK_M_IX锁的本质
LCK_M_IX是意向排他锁,属于SQL Server多粒度锁机制里的表级(或页级)锁,核心是个“信号锁”:
- 它会告诉其他事务:当前事务已经在该表的某个行/页上持有排他锁(X),或者即将去申请行/页级的排他锁
- 它本身不会阻塞常规的查询、单条更新操作,只会拦截需要获取整张表排他锁的操作(比如
ALTER TABLE、全表锁写操作) - 它是SQL Server自动隐式添加的,不需要手动指定
二、快速重现LCK_M_IX锁的步骤
1. 准备测试表
先创建一张带主键的测试表,确保行级锁能正常生效:
CREATE TABLE TestLock (ID INT PRIMARY KEY, Value VARCHAR(50)); INSERT INTO TestLock VALUES (1, '初始值');
2. 会话1:开启事务并持有行级排他锁
打开第一个SQL Server查询窗口,执行以下语句(不要提交或回滚事务):
BEGIN TRAN; -- 更新某一行,此时该行会被加X锁,SQL Server自动在表级加IX锁 UPDATE TestLock SET Value = '已更新' WHERE ID = 1;
3. 会话2:查询表级锁信息
打开第二个查询窗口,执行锁查询语句,过滤目标表的锁:
SELECT resource_type, -- 锁的层级(OBJECT=表,KEY=行) request_mode, -- 锁模式(IX=意向排他,X=排他) resource_description FROM sys.dm_tran_locks WHERE resource_associated_entity_id = OBJECT_ID('TestLock');
执行后就能看到一条resource_type为OBJECT、request_mode为IX的记录,这就是你要找的LCK_M_IX锁。同时还能看到行级的KEY类型、X模式的锁。
另一种重现场景:插入行不提交
会话1执行插入语句不提交,同样会触发表级IX锁:
BEGIN TRAN; INSERT INTO TestLock VALUES (2, '新行'); -- 不提交事务
再用会话2的查询语句,依然能抓到表级IX锁。
三、LCK_M_IX锁的产生原因
SQL Server采用多粒度锁层级(表→页→行),意向锁的设计是为了避免低效的冲突检查:
- 如果没有意向锁,当一个事务要申请整张表的排他锁时,需要遍历表中所有行/页的锁来确认冲突,大表上会极慢
- 意向锁(包括IX、IU、IS)相当于在表/页级提前标记“已有事务在下层持有锁”,其他事务要申请表级锁时,直接看表级的意向锁就能快速判断冲突
- 当事务在某个行/页上持有排他锁(X),或者显式/隐式申请行/页级排他锁时,SQL Server会自动在上级层级(表/页)添加对应的意向排他锁(IX)
内容的提问来源于stack exchange,提问作者kosnkov
相关产品推荐
相关产品推荐

