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,且不會嚴重到之前終止會話的錯誤
關於嚴重級別 和 描述:
https://docs.microsoft.com/zh-cn/sql/relational-databases/errors-events/database-engine-error-severities?view=sql-server-2017 “數據庫引擎錯誤嚴重性”
那我們前面的例子錯誤級別16,的確是屬於可以捕捉的情況。那為什么會有這個問題。跟執行計划的產生有關系。因為你第一次執行的時候,SQL server 在需要編譯SQL 語句,產生執行計划。就是這個時候執行計划還沒有。所以他無法往下面繼續執行。就無法CATCH到。第二次,以及后面幾次再執行,因為已經緩存了執行計划。所以可以catch到。
我們執行完第一次之后可以查看對應的執行計划
然后再執行,就可以成功捕捉了。如果我們把執行計划清除掉
DBCC FREEPROCCACHE 或者使用option(recomplile)進行重編譯。那么結果就會是一直無法捕捉。 
