並發事務互相持有鎖並請求對方持有的鎖,形成循環等待。SQL Server會選擇犧牲者拋出錯誤1205並回滾。
T-SQL無法捕獲異常,死鎖發生後腳本終止,無法實現重試邏輯。
SET XACT_ABORT ON;
DECLARE @retry INT = 1, @maxRetry INT = 3;
WHILE @retry <= @maxRetry
BEGIN
BEGIN TRAN;
BEGIN TRY
INSERT INTO Orders(CustomerId) VALUES('ALFKI');
WAITFOR DELAY '00:00:05';
SELECT * FROM Orders WHERE CustomerId = 'ALFKI';
COMMIT;
BREAK; -- 成功跳出循環
END TRY
BEGIN CATCH
ROLLBACK;
WAITFOR DELAY '00:00:03'; -- 關鍵:等待減少衝突
SET @retry += 1;
CONTINUE;
END CATCH;
END;
超過重試次數後使用RAISERROR重新拋出原始錯誤信息,避免錯誤被吞沒:
IF @retry > @maxRetry
BEGIN
DECLARE @msg NVARCHAR(2048) = ERROR_MESSAGE();
RAISERROR(@msg, 16, 1);
END