兩個連線 5 秒內同時執行特定插入/查詢序列會產生死結。SQL Server 犧牲一個連線拋出異常回滾。SQL Server 2000 中異常發生後 T-SQL 停止執行,PRINT 等後續陳述式不會執行,難以在 T-SQL 內處理死結。
支援 T-SQL 結構化錯誤處理,提供死結重試路徑。
SET XACT_ABORT ON;
DECLARE @r INT = 1;
WHILE @r <= 3
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 @r = @r + 1;
CONTINUE;
END CATCH;
END;
關鍵點:ROLLBACK 後必須 WAITFOR DELAY 讓衝突釋放;@retry 可依需求調整。
重試超過上限後異常被吞沒。SQL Server 2005 提供 RAISERROR 但無法直接拋出原始異常,需重新定義錯誤資訊:
IF ERROR_NUMBER() <> 0
BEGIN
DECLARE @ErrorMessage NVARCHAR(4000), @ErrorSeverity INT, @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END;
期待未來版本提供無參數 RAISERROR 直接重拋原始異常。
將死結處理封裝於 T-SQL 內,明確職責分離,上層資料存取程式碼無需關心死結邏輯,提升系統清晰度。