首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> SQL Server 2005

SQL Server 2005/2008 TRY...CATCH 異常處理完整指南

     編輯:SQL Server 2005

TRY...CATCH 是 SQL Server 2005 引入的結構化錯誤處理機制,極大提升了 T-SQL 的健壯性與可維護性,其語法風格與 C#、Java 等主流語言一脈相承,降低了開發者的認知負擔。

一、SQL Server 2000 時代的痛苦:@@ERROR 檢查地獄

在 2000 版本中,每執行一條 DML 語句後必須立即檢查 @@ERROR 全域變數,因為它會被下一條語句覆蓋。典型的轉帳存儲過程充滿了巢狀 IF @@ERROR != 0 判斷與 ROLLBACK/RETURN,代碼冗長且極易遺漏檢查點:

CREATE PROC usp_AccountTransaction @AccountNum INT, @Amount DECIMAL AS
BEGIN
  BEGIN TRANSACTION
  UPDATE MyChecking SET Amount = Amount - @Amount WHERE AccountNum = @AccountNum
  IF @@ERROR != 0 BEGIN ROLLBACK TRANSACTION; RETURN END
  UPDATE MySavings SET Amount = Amount + @Amount WHERE AccountNum = @AccountNum
  IF @@ERROR != 0 BEGIN ROLLBACK TRANSACTION; RETURN END
  COMMIT TRANSACTION
END

二、TRY...CATCH 核心語法與錯誤資訊函數

基本結構

BEGIN TRY
  -- 可能拋出錯誤的陳述式
END TRY
BEGIN CATCH
  -- 錯誤處理邏輯:記錄、回滾、重拋等
END CATCH

CATCH 區塊專用系統函數

函數說明
ERROR_NUMBER()錯誤號碼
ERROR_SEVERITY()嚴重等級
ERROR_STATE()狀態碼
ERROR_PROCEDURE()發生錯誤的預存程序名稱
ERROR_LINE()錯誤行號
ERROR_MESSAGE()完整錯誤訊息文字

關鍵限制:以上函數僅在 CATCH 區塊內有效,若在外部呼叫將回傳 NULL。

簡易示範:除零錯誤捕捉

BEGIN TRY
  SELECT GETDATE();
  SELECT 1/0;  -- 故意觸發除零錯誤
END TRY
BEGIN CATCH
  SELECT '發生錯誤:' + ERROR_MESSAGE();
  RETURN;
END CATCH;

三、事務控制實戰範本

ALTER PROC usp_AccountTransaction @AccountNum INT, @Amount DECIMAL AS
BEGIN
  BEGIN TRY
    BEGIN TRANSACTION;
    UPDATE MyChecking SET Amount = Amount - @Amount WHERE AccountNum = @AccountNum;
    UPDATE MySavings SET Amount = Amount + @Amount WHERE AccountNum = @AccountNum;
    COMMIT TRAN;  -- 成功提交
  END TRY
  BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRAN;  -- 回滾未提交事務
    -- 重新拋出原始錯誤給上層呼叫者
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1);
  END CATCH
END

四、完整錯誤日誌實作

1. 建立錯誤日誌表

CREATE TABLE ErrorLog (
  ErrNum INT, ErrSev NVARCHAR(1000), ErrState INT,
  ErrProc NVARCHAR(1000), ErrLine INT, ErrMsg NVARCHAR(2000)
);

2. 錯誤記錄預存程序

CREATE PROCEDURE usp_LogError AS
BEGIN
  INSERT INTO ErrorLog
  VALUES (ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_STATE(),
          ERROR_PROCEDURE(), ERROR_LINE(), ERROR_MESSAGE());
END

3. 實務範例:查詢當日生日會員

ALTER PROCEDURE dbo.getTodayBirthday AS
BEGIN TRY
  DECLARE @today DATETIME = GETDATE();
  DECLARE @day VARCHAR(2) = REPLACE(DAY(@today), '0', '');
  DECLARE @month VARCHAR(2) = REPLACE(MONTH(@today), '0', '');
  DECLARE @year VARCHAR(4) = YEAR(@today);

  SELECT * FROM dbo.UserInfo
  WHERE REPLACE(DAY(CONVERT(DATETIME, Birthday)), '0', '') = @day
    AND REPLACE(MONTH(CONVERT(DATETIME, Birthday)), '0', '') = @month
    AND Birthday IS NOT NULL;
END TRY
BEGIN CATCH
  EXEC usp_LogError;  -- 記錄完整錯誤上下文
END CATCH

五、關鍵提醒

  • TRY...CATCH 無法捕捉 編譯錯誤(語法錯誤)、連線中斷、或嚴重度 > 20 的系統錯誤。
  • 嵌套 TRY...CATCH 時,錯誤會冒泡到最近的外層 CATCH。
  • 配合 XACT_ABORT ON 可確保嚴重錯誤自動回滾事務,進一步簡化代碼。

掌握 TRY...CATCH 讓 T-SQL 具備現代語言級的錯誤處理能力,是每位 SQL Server 開發者的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved