在 SQL Server 2000 中,若存儲過程內發生嚴重錯誤(如除零、轉換失敗),批次會直接終止,後續的 IF @@ERROR != 0 判斷根本不會執行,導致事務無法回滾,數據處於不一致狀態。
CREATE PROCEDURE test_tran
AS
SET XACT_ABORT ON; -- 關鍵:遇嚴重錯誤自動回滾整個事務並中止批次
BEGIN TRANSACTION RemoteUpdate;
INSERT psn_degree VALUES (22, 'test');
SELECT 1/0; -- 故意製造除零錯誤
IF @@ERROR != 0
BEGIN
ROLLBACK TRANSACTION RemoteUpdate;
RAISERROR('出錯!網絡速度慢或斷線!', 16, 16) WITH SETERROR;
RETURN; -- 必須 RETURN,否則會繼續向下執行 COMMIT
END
ELSE
BEGIN
COMMIT TRANSACTION RemoteUpdate;
END
GO
CREATE PROCEDURE test_tran
AS
SET XACT_ABORT ON;
BEGIN TRANSACTION RemoteUpdate;
INSERT psn_degree VALUES (22, 'test');
SELECT 1/0;
IF @@ERROR != 0
BEGIN
ROLLBACK TRANSACTION RemoteUpdate;
RAISERROR('出錯!', 16, 1) WITH SETERROR;
RETURN;
END
COMMIT TRANSACTION RemoteUpdate; -- 正常路徑隱式提交
GO
TRY...CATCH。@@ERROR 僅捕獲非致命錯誤;嚴重錯誤會跳過後續語句,必須靠 XACT_ABORT 保證回滾。RETURN 後不可再有代碼,否則邏輯錯亂。RAISERROR ... WITH SETERROR 將 @@ERROR 置為非零,便於客戶端感知。CREATE PROCEDURE ModernTran
AS
BEGIN
SET XACT_ABORT ON; -- 依然建議保留
BEGIN TRY
BEGIN TRANSACTION;
INSERT psn_degree VALUES (22, 'test');
SELECT 1/0;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW; -- 重新拋出原始錯誤,保留堆疊
END CATCH
END
老版本靠 SET XACT_ABORT ON 兜底,新版本用 TRY...CATCH 更優雅。無論哪個時代,事務要么全成要么全敗 是不變的鐵律。