- 錯誤可能發生執行的各個階段,包括語法檢查階段、對象名稱識別階段、語句執行階段;錯誤即可以在數據庫引擎中處理,也可以在應用程序中處理
- 錯誤類型,根據錯誤發生時機區分:
- Syntax Errors,語法錯誤
- Object Resolution Errors,對象識別錯誤
- Statement Terminating Errors,語句終止錯誤,發生錯誤的下一條語句繼續執行
- Batch、Connection、Server Terminating Errors,通常都是非常嚴重的錯誤,比如硬件錯誤,非常少見
- 錯誤本身也是一個對象,具有如下屬性:
- Error number:唯一的錯誤編碼
- Error Message:錯誤信息,經過了本地化,使用sys.messages視圖查看信息時,為每個message_id(即Error number)返回對個message,每個message對應不同的language_id,即對應不同語言
- Severity,嚴重性
- State,決定發生錯誤的代碼的位置,是在代碼中中由開發者定義的,在raise error中可以指定一個state
- Procedure Name,存儲過程或者觸發器的名稱,如果有的話
- Line Number,表明發生錯誤的代碼行
- 錯誤嚴重性:
- 0-9,信息
- 10,返回狀態的信息
- 11-16,需要用戶糾正的錯誤,比如11表示對象不存在,13表示事務死鎖,14表示像沒有權限這樣的錯誤,15表示語法錯誤
- 17-19,用戶無法糾正的軟件錯誤,比如17表示資源用盡(比如內存、磁盤空間、鎖等資源)
- 20-24,嚴重的系統錯誤
- 25,SQL Server服務終端錯誤
- RAISE ERROR和PRINT都可以返回信息或者錯誤,PRINT相當於返回Severity為10的信息;%d是數字占位符,%s是字符串占位符;有兩種方式,一種是使用sp_addmessage創建用戶自定義的錯誤信息,一種是指定錯誤字符串,此時error number總是5000
- @@ERROR是一個系統變量,保存上次發生錯誤的error number,如果語句成功執行返回0,否則返回error number,每個語句執行完都要修改該值,因為只要錯誤一出現就要盡快捕獲該值
- 大部分錯誤是語句終止錯誤,即只有發生錯誤的語句回滾,然后繼續執行下一條語句;當設置SET XACT_ABORT ON語句時,語句終止錯誤應該變為批處理終止錯誤,即語句發生錯誤時,整個批處理進行回滾,而不僅僅是單個語句回滾
- SQL Server不支持自治事務autonomous transactions,自治事務就是不在同一個范圍內的嵌套事務,其提交和回滾不影響外部事務;@@TRANCOUNT系統變量返回事務嵌套層級,存儲過程要求在開始和退出時@@TRANCOUNT必須是一致的,否則拋出錯誤286,通常用來防止嵌套事務
- sp_addmessage允許添加自定義的錯誤信息,指定的error number必須是50000或者以上,可以指定語言(@lang參數),@with_log設置為true時,返回錯誤時會將錯誤記錄到Windows Application log,@replace用於替換已有的自定義消息的Message,使用該系統存儲過程時,必須具有sysadmin或者serveradmin權限;注意不能引發系統錯誤
- BEGIN CATCH語句必須跟在END TRY之后;在T-SQL中沒有等價於FINALLY的語句,沒有rethrowing機制,只有大於50000的錯誤可以手工拋出,即不能在CATCH語句中引發一個系統錯誤
- CATCH語句塊為捕獲錯誤信息提供了比@@ERROR更豐富的選擇,可以在CATCH語句塊中執行錯誤處理函數,返回錯誤信息,錯誤處理函數還可以定義成存儲過程以便重用,這些錯誤處理函數在整個CATCH語句塊中始終都保持同一個值,不存在像@@ERROR值被輕易修改的問題
- 不是所有的錯誤都可以在當前范圍的TRY/CATCH語句塊中捕獲,通常來說,在當前范圍不能捕獲的錯誤,可以在包含他們的范圍內捕獲,比如不能在存儲過程內部TRY/CATCH語句塊中捕獲的錯誤,可以在調用存儲過程的TRY/CATCH語句塊中捕獲;通常不能捕獲的錯誤包括:編譯錯誤、語句級別重新編譯問題(通常是名稱識別錯誤)
- CATCH語句塊不會自動回滾異常,需要在CATCH語句塊中手動回滾異常
- 通常來說盡量在托管代碼中捕獲異常,所有托管代碼中未捕獲的異常,傳遞到T-SQL代碼中都是一個6522的錯誤,錯誤信息可以嵌套,SQL CLR Messages需要解包去找到內部錯誤,而不是封裝的6522錯誤,托管代碼中也可以執行RAISERROR語句
