兩個或多個 Session 互相持有鎖並請求對方持有的鎖,形成循環等待。SQL Server 死鎖監視器會選擇犧牲者(通常是回滾成本最低者)終止,回傳錯誤 1205。
-- 表 goods_sort
CREATE TABLE goods_sort (iSortID INT PRIMARY KEY IDENTITY(1001,1), sSortName NVARCHAR(20));
INSERT INTO goods_sort VALUES ('服飾'),('女包'),('鞋子'),('首飾'),('美容');
-- 表 goods
CREATE TABLE goods (iID INT PRIMARY KEY IDENTITY, iGoodsID VARCHAR(20), sGoodsName NVARCHAR(100), iGoodTotal INT DEFAULT 0, iPrice INT DEFAULT 0, iPriceTotal INT, iSortID INT, tAddDate SMALLDATETIME DEFAULT GETDATE());
INSERT INTO goods VALUES ('YR6001','瘦身羽絨服',20,200,4000,1001),('YR6002','加厚羽絨服',20,300,6000,1001),('BB7001','小黃牛皮馬鞍包',30,100,3000,1002),('BB7002','十字繡流蘇包',50,150,7500,1002);
SET NOCOUNT ON; SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN
UPDATE goods_sort SET sSortName='女鞋' WHERE iSortID=1003;
WAITFOR DELAY '00:00:05'; -- 增加持鎖時間
UPDATE goods SET sGoodsName='胖子羽絨服' WHERE iID=2;
COMMIT TRAN
END TRY
BEGIN CATCH
IF XACT_STATE()=-1 ROLLBACK TRAN;
IF ERROR_NUMBER()=1205 PRINT '事務 1 發生死鎖';
END CATCH
SELECT * FROM goods WHERE iID=2;
SELECT * FROM goods_sort WHERE iSortID=1003;
SET NOCOUNT ON; SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN
UPDATE goods SET sGoodsName='瘦子羽絨服' WHERE iID=2;
WAITFOR DELAY '00:00:05';
UPDATE goods_sort SET sSortName='男鞋' WHERE iSortID=1003;
COMMIT TRAN
END TRY
BEGIN CATCH
IF XACT_STATE()=-1 ROLLBACK TRAN;
IF ERROR_NUMBER()=1205 PRINT '事務 2 發生死鎖';
END CATCH
SELECT * FROM goods WHERE iID=2;
SELECT * FROM goods_sort WHERE iSortID=1003;
TRY-CATCH 確保錯誤後仍能執行後續查詢/記錄。WAITFOR DELAY 擴大死鎖窗口,穩定複現。ERROR_NUMBER()=1205 精確識別死鎖,寫入 SQL Server Log 或應用日誌。XACT_STATE()=-1 判斷不可提交交易,必須回滾。1204 / 1222 或擴充事件 xml_deadlock_report 記錄死鎖圖。ROWLOCK / UPDLOCK 提示精細控制。