1. 程式人生 > >SQL Server Try Catch 異常捕捉

SQL Server Try Catch 異常捕捉

背景

今天遇到一個關於try catch 使用比較有意思的問題。如下一段程式碼:

SELECT  @@TRANCOUNT AS A
BEGIN TRY  
            BEGIN TRAN
            SELECT  @@TRANCOUNT AS A1

            INSERT  INTO A2A ( ID1 )
            VALUES  ( 'A' )

            COMMIT TRAN;  
END TRY  
BEGIN CATCH  
            SELECT  @@TRANCOUNT AS A2

            ROLLBACK
TRAN;
SELECT ERROR_MESSAGE() AS ErrorMessage , ERROR_SEVERITY() AS ErrorSeverity , ERROR_STATE() AS ErrorState END CATCH SELECT @@TRANCOUNT AS B

第一次執行時,無法正常捕捉到錯誤,並執行catch的程式碼,返回錯誤資訊
這裡寫圖片描述
第二次執行,就能正常捕捉。且後續再執行就都正常了。
這裡寫圖片描述
同樣的程式碼,執行2次出現完全不同的結果。這是很讓人費解的。

分析

首先 看第一次執行報錯,看這個錯誤的級別編號是16。
try catch 不能捕捉什麼樣的錯誤

嚴重級別為 10 或更低的錯誤,屬於警告或資訊性訊息。
嚴重級別為 20 或更高且終止會話的 SQL Server 資料庫引擎任務處理的錯誤。此類問題過於嚴重資料庫引擎會直接終止會話。所以無法往後繼續執行。

總之,就是能捕捉嚴重級別大於10,且不會嚴重到之前終止會話的錯誤

那我們前面的例子錯誤級別16,的確是屬於可以捕捉的情況。那為什麼會有這個問題。跟執行計劃的產生有關係。因為你第一次執行的時候,SQL server 在需要編譯SQL 語句,產生執行計劃。就是這個時候執行計劃還沒有。所以他無法往下面繼續執行。就無法CATCH到。第二次,以及後面幾次再執行,因為已經快取了執行計劃。所以可以catch到。

我們執行完第一次之後可以檢視對應的執行計劃
這裡寫圖片描述
然後再執行,就可以成功捕捉了。如果我們把執行計劃清除掉
DBCC FREEPROCCACHE 或者使用option(recomplile)進行重編譯。那麼結果就會是一直無法捕捉。
這裡寫圖片描述