群里一個朋友遇到一個TRY CATCH的小問題,測試后發現是自己從來沒有考慮的情況,寫篇blog加深下印象
--=========================================================
在MSDN上對TRY CATCH有如下描述:
對 Transact-SQL 實現與 Microsoft Visual C# 和 Microsoft Visual C++ 語言中的異常處理類似的錯誤處理。Transact-SQL 語句組可以包含在 TRY 塊中。如果 TRY 塊內部發生錯誤,則會將控制傳遞給 CATCH 塊中包含的另一個語句組。
--=========================================================
在TRY CATCH未出現之前,我們使用@@ERROR,ERROR_STATE()等來判斷語句是否正常運行,再根據情況來處理事務,隨著TRY CATCH的出現,我們可以將事務語句寫成如下方式:
--開啟事務BEGIN TRAN BEGIN TRY --執行一些邏輯操作 INSERT INTO TB1(ID)VALUES(1) --提交事務 COMMIT TRANEND TRYBEGIN CATCH --回滾事務 ROLLBACK TRANEND CATCH
可當我們執行以下語句(不創建臨時表#TB)
BEGIN TRAN BEGIN TRY INSERT INTO #TB SELECT 1 PRINT 'COMMIT TRAN'; COMMIT TRAN;END TRYBEGIN CATCH SELECT ERROR_MESSAGE() AS ErrorMessage ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_STATE() AS ErrorState PRINT 'ROLLBACK TRAN'; ROLLBACK TRAN;END CATCH
由于#TB沒有創建,因此在執行中發生異常,錯誤提示如下:
消息 102,級別 15,狀態 1,第 24 行“對”附近有語法錯誤。
這個錯誤很容易理解,因為#TB不存在,但這不是重點,重點是CATCH部分的語句沒有被執行,事務沒有被提交也沒有被回滾(如果程序中有類似問題,那就嚴重咯)。
繼續閱讀MSDN,可以找到如下解釋:
不受 TRY…CATCH 構造影響的錯誤TRY…CATCH 構造在下列情況下不捕獲錯誤:嚴重級別為 10 或更低的警告或信息性消息。嚴重級別為 20 或更高且終止會話的 SQL Server 數據庫引擎任務處理的錯誤。如果所發生錯誤的嚴重級別為 20 或更高,而數據庫連接未中斷,則 TRY…CATCH 將處理該錯誤。需要關注的消息,如客戶端中斷請求或客戶端連接中斷。當系統管理員使用 KILL 語句終止會話時。如果以下類型的錯誤的發生級別與 TRY…CATCH 構造的執行等級相同,則 CATCH 塊不會處理這些錯誤:編寫錯誤,例如禁止運行批處理的語法錯誤。語句級重新編寫過程中出現的錯誤,例如由于名稱解析延遲而造成在編寫后出現對象名解析錯誤。這些錯誤會被返回到運行批處理、存儲過程或觸發器的級別。
經過對比分析,我們遇到的問題應該屬于“語句級重新編寫過程中出現的錯誤,例如由于名稱解析延遲而造成在編寫后出現對象名解析錯誤。”的情況。
--==============================================================
如果有類似的問題,我們應該如何處理呢?
解決辦法1: 在對#TB處理前先判斷其是否存在
解決辦法2:將對#TB的操作語句放入的EXEC(@SQL)
BEGIN TRAN BEGIN TRY EXEC('INSERT INTO #TB SELECT 1') PRINT 'COMMIT TRAN'; COMMIT TRAN;END TRYBEGIN CATCH SELECT ERROR_MESSAGE() AS ErrorMessage ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_STATE() AS ErrorState PRINT 'ROLLBACK TRAN'; ROLLBACK TRAN;END CATCH
執行以上代碼,會發現同樣是嚴重級別16的錯誤,這次可以被傳遞到CATCH塊中處理。--=======================================================
很多人說細節決定成敗,學習SQL SERVER的路上,有很多類似的小知識點,平時很難遇到,遇到時也很容易顛覆下我們自認為的“真理”,這個時候,多看看MSDN還是很管用的!
新聞熱點
疑難解答