环境: sqlserver 2008
事务(进程 ID (n))与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品。请重新运行
死锁原理:
如两个任务
任务1,已经锁定R1,再进行请求R2
任务2,已经锁定R2,再进行请求R1
导致两个任务都进入了阻塞。SQLSERVER会选择一个进行牺牲。
了解了原理后,来段SQL
-- 表结构和模拟数据CREATETABLE R1(
ID INTNOTNULL,
Name varchar(50)NULL,
Num INTNULLCONSTRAINT[PK_R1]PRIMARYKEYCLUSTERED
(
[ID]ASC)
WITH(PAD_INDEX=OFF, STATISTICS_NORECOMPUTE=OFF,
IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS=ON,
ALLOW_PAGE_LOCKS =ON)
ON[PRIMARY]) ON[PRIMARY]GOINSERTINTOR1(ID, Name, Num)VALUES(1,'张三',50)INSERTINTOR1(ID, Name, Num)VALUES(2,'李四',50)CREATETABLE R2(
ID INTNOTNULL,
Name varchar(50)NULL,
Num INTNULLCONSTRAINT[PK_R2]PRIMARYKEYCLUSTERED
(
[ID]ASC)
WITH(PAD_INDEX=OFF, STATISTICS_NORECOMPUTE=OFF,
IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS=ON,
ALLOW_PAGE_LOCKS =ON)
ON[PRIMARY]) ON[PRIMARY]GOINSERTINTOR2(ID, Name, Num)VALUES(1,'张三',50)INSERTINTOR2(ID, Name, Num)VALUES(2,'李四',50)
任务1:
begin tran t1
-- R1
update [dbtest].[dbo].[R1] SET Num = 91 WHERE Name = '张三'
-- R2
update [dbtest].[dbo].[R2] SET Num = 91 WHERE Name = '李四'
rollback tran t1
任务2:
begin tran t2
-- R2
update [dbtest].[dbo].[R2] SET Num = 91 WHERE Name = '李四'
-- R1
update [dbtest].[dbo].[R1] SET Num = 91 WHERE Name = '张三'
rollback tran t2
执行方法:
1.在任务1里面执行前两句(开启事务, 锁定R1)
2.然后切换到任务2里面执行前两句(开启事务, 锁定R2)
3.在任务1里面执行锁定R2(update R2…)此时要请求的R2被任务2锁定
4.在任务2里面执行锁定R1(Update R1…)此时请求的R1被任务1锁定。
进入了死锁,然后会弹出死锁的信息。
消息 1205,级别 13,状态 51,第 2 行
事务(进程 ID 89)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。