能否在SQL Server中无需修改表,实现两个进程的死锁模拟?
在SQL Server中无需修改表模拟死锁的可行方案
完全可行,不需要修改表数据,通过事务内的共享锁持有+循环锁等待就能模拟死锁,以下是具体操作步骤(以存在数据的Person.Person表为例,换成你自己的业务表也可以):
步骤1:打开两个独立的SQL Server查询会话
比如在SSMS里打开两个新的查询窗口,分别作为会话A和会话B。
会话A操作:
开启事务,查询并锁定第一部分数据(锁会保持到事务结束):
BEGIN TRANSACTION; -- 用HOLDLOCK让共享锁持有至事务结束,ROWLOCK指定行级锁 SELECT * FROM Person.Person WHERE BusinessEntityID BETWEEN 1 AND 100 WITH (HOLDLOCK, ROWLOCK);
会话B操作:
同样开启事务,查询并锁定另一部分数据:
BEGIN TRANSACTION; SELECT * FROM Person.Person WHERE BusinessEntityID BETWEEN 101 AND 200 WITH (HOLDLOCK, ROWLOCK);
触发死锁:
- 回到会话A,执行查询请求会话B持有的锁:
SELECT * FROM Person.Person WHERE BusinessEntityID BETWEEN 101 AND 200 WITH (HOLDLOCK, ROWLOCK);
- 立刻切换到会话B,执行查询请求会话A持有的锁:
SELECT * FROM Person.Person WHERE BusinessEntityID BETWEEN 1 AND 100 WITH (HOLDLOCK, ROWLOCK);
此时SQL Server的死锁检测机制会立刻触发,其中一个会话会收到死锁错误提示(通常是Msg 1205, Level 13, State 51),事务自动回滚,另一个会话可以继续执行。
原理说明:
HOLDLOCK(等价于SERIALIZABLE隔离级别的锁行为)会让查询获取的共享锁一直持有到事务提交/回滚,而不是默认的查询结束就释放。- 两个会话先分别持有不同范围的行锁,之后互相请求对方持有的锁,形成循环等待链,满足死锁的四个必要条件(互斥、请求与保持、不可剥夺、循环等待),从而触发死锁。
内容的提问来源于stack exchange,提问作者Jaybee72
相关产品推荐
相关产品推荐

