模拟 SQLSERVER 死锁

环境: 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)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。

你可能感兴趣的:(模拟 SQLSERVER 死锁)