如何在SQL Server上模拟DEADLOCK?

use*_*473 32 sql sql-server concurrency deadlock

我试图模拟SQL Server上的死锁.

_|worker_id|salary|
1|1        |100   |
2|2        |300   |
Run Code Online (Sandbox Code Playgroud)

交易1在5秒内完成.

/* TRANSACTION 1*/
Use dbmcw;

DECLARE @sal1 INT, @sal2 int;

BEGIN TRAN;

SELECT @sal1 = salary
FROM dbo.deadlock_demonstration WITH(UPDLOCK) 
WHERE worker_id = 1;

WAITFOR DELAY '00:00:05.000';

SELECT @sal2 = salary
FROM dbo.deadlock_demonstration WITH(UPDLOCK)
WHERE worker_id = 2;

COMMIT TRAN;
Run Code Online (Sandbox Code Playgroud)

交易2在3秒内完成.

/* TRANSACTION 2*/
Use dbmcw;

DECLARE @sal1 INT, @sal2 int;

BEGIN TRAN;

SELECT @sal2 = salary
FROM dbo.deadlock_demonstration WITH(UPDLOCK)
WHERE worker_id = 2;

SELECT @sal1 = salary
FROM dbo.deadlock_demonstration WITH(UPDLOCK)
WHERE worker_id = 1;

COMMIT TRAN;
Run Code Online (Sandbox Code Playgroud)

SQL Server没有给出任何错误.死锁没有发生.为了模拟死锁,我应该改变什么?

Dav*_*son 49

您可以使用下面显示的步骤创建死锁.首先,使用样本数据创建全局临时表.

--Two global temp tables with sample data for demo purposes.
CREATE TABLE ##Employees (
    EmpId INT IDENTITY,
    EmpName VARCHAR(16),
    Phone VARCHAR(16)
)
GO

INSERT INTO ##Employees (EmpName, Phone)
VALUES ('Martha', '800-555-1212'), ('Jimmy', '619-555-8080')
GO

CREATE TABLE ##Suppliers(
    SupplierId INT IDENTITY,
    SupplierName VARCHAR(64),
    Fax VARCHAR(16)
)
GO

INSERT INTO ##Suppliers (SupplierName, Fax)
VALUES ('Acme', '877-555-6060'), ('Rockwell', '800-257-1234')
GO
Run Code Online (Sandbox Code Playgroud)

现在在SSMS中打开两个空查询窗口.将会话1的代码放在一个查询窗口中,将会话2的代码放在另一个查询窗口中.然后逐步执行两个会话中的每个会话,根据需要在两个查询窗口之间来回切换.请注意,每个事务都锁定了另一个事务也请求锁定的资源.

Session 1                   | Session 2
===========================================================
BEGIN TRAN;                 | BEGIN TRAN;
===========================================================
UPDATE ##Employees
SET EmpName = 'Mary'
WHERE EmpId = 1
===========================================================
                             | UPDATE ##Suppliers
                             | SET Fax = N'555-1212'
                             | WHERE SupplierId = 1
===========================================================
UPDATE ##Suppliers
SET Fax = N'555-1212'
WHERE SupplierId = 1
===========================================================
<blocked>                    | UPDATE ##Employees
                             | SET Phone = N'555-9999'
                             | WHERE EmpId = 1
===========================================================
                             | <blocked>
===========================================================
Run Code Online (Sandbox Code Playgroud)

导致死锁; 一个事务完成,另一个事务中止,错误消息1205被发送到客户端.

关闭"会话1"和"会话2"的SSMS查询窗口以提交(或回滚)任何打开的事务.最后,清理临时表:

DROP TABLE ##Employees
GO
DROP TABLE ##Suppliers
GO
Run Code Online (Sandbox Code Playgroud)

  • 注意:为了有效地运行它,我所做的是将所有“==”查找/替换为“--”,粘贴到两个查询窗口中,然后在 SSMS 中使用 Alt+Drag 来选择我想要的脚本的各个部分跑步。在 SSMS 2012 及更高版本中,您可以按住 alt 并拖动以创建矩形文本选择 (3认同)
  • 如果他们编辑不同的记录,则不会发生死锁。我对吗? (2认同)