DDL 語句上的錯誤永遠不會呼叫 CATCH
當我嘗試關閉下面的 SS Management Studio 視窗時出現錯誤
我知道 DDL 語句是隱式 COMMIT 並且下面的 WARNING 消息是因為 BEGIN TRAN 從不 COMMIT 或 ROLLBACK。Alter DDL 語句中止並且從未循環通過 CATCH 塊。無法理解為什麼在錯誤之後控制沒有傳遞給 CATCH 塊(這確實發生在任何其他 DML 語句中)您能否解釋為什麼 CATCH 中的語句從未針對此 DDL 錯誤執行?
為什麼沒有抓到?因為 TRY / CATCH 不能擷取所有類型的錯誤。但是您可以通過將其包裝在 EXEC() 中來擷取非系統關鍵的內容,例如:
BEGIN TRY EXEC('ALTER TABLE...'); END TRY
ALTER 中的錯誤將失敗到 EXEC,而 EXEC 又將返回到 TRY / CATCH 塊,報告一個簡單的、可擷取的錯誤。
有關更多詳細資訊,TRY…CATCH的 MSDN 頁面指出:
以下類型的錯誤發生在與 TRY…CATCH 構造相同的執行級別時,不會由 CATCH 塊處理:
- 編譯錯誤,例如語法錯誤,阻止批處理執行。
- 在語句級重新編譯期間發生的錯誤,例如由於延遲名稱解析而在編譯後發生的對象名稱解析錯誤。
關於對象名稱解析錯誤的第二個要點是導致 ALTER 語句失敗並且沒有資格由 CATCH 塊處理的原因。
編輯:
關於您關於“DDL 語句是隱式送出”的聲明:我不確定您的意思是什麼,但是所有(嗯,幾乎所有)查詢本身都是事務。意思是,單查詢批處理對顯式
BEGIN TRAN
/COMMIT
/沒有用處ROLLBACK
。如果語句失敗,它會自動回滾,如果成功,則自動送出。如果您出於某種原因想要有條件地回滾,您只會使用BEGIN TRAN
//構造。使用該結構來正確處理錯誤仍然是一個好主意,但是通過顯式事務處理,您將一無所獲(至少對於問題中發布的程式碼)。發布的程式碼與以下程式碼之間絕對沒有區別:COMMIT``ROLLBACK``TRY...CATCH
BEGIN TRY EXEC('ALTER TABLE...'); END TRY BEGIN CATCH SELECT 'I''m in Catch'; END CATCH;
出現此錯誤是因為不滿足 ALTER 命令,可能是由於任何原因。表不存在等。在這種情況下,Begin Tran 開始了,但它沒有通過..所以它無法送出。因此,當您關閉會話時,SSMS 會詢問“有未送出的事務。您希望在關閉視窗之前送出這些事務嗎?” .. 因為事務已開始,但既沒有送出也沒有回滾。
在 SQL Server 中,事務是自動送出的,但如果您在 “Begin Tran -Commit” 中特別提到了任何查詢,它應該以送出或回滾完成