2010-06-10 56 views
1

假設我想告訴應用程序發生了什麼/返回了SQL服務器。我們有這樣的代碼塊:SQL嘗試catch目的不清楚

BEGIN TRY 
    -- Generate divide-by-zero error. 
    SELECT 1/0; 
END TRY 
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber, 
     ERROR_SEVERITY() AS ErrorSeverity, 
     ERROR_STATE() as ErrorState, 
     ERROR_PROCEDURE() as ErrorProcedure, 
     ERROR_LINE() as ErrorLine, 
     ERROR_MESSAGE() as ErrorMessage; 
END CATCH; 
GO 

,並讓我們有這樣的代碼塊:

SELECT 1/0; 

我的問題是: 兩個零錯誤返回分工。我不明白的是,爲什麼當我在兩種情況下都遇到錯誤時,我應該用try catch clausule來包圍它? 是不是這個錯誤會在兩種情況下傳播到客戶端應用程序?

回答

3

是的,Try Catch的唯一原因是(如在普通代碼中),如果您可以「處理」錯誤,即,你可以糾正錯誤併成功地完成程序的任務功能,或者如果想在錯誤返回給客戶端之前做一些事情(比如修改消息,或者將它存儲在錯誤日誌表中或者發送給別人一封電子郵件等(儘管我更喜歡從DAL層中完成大部分工作)

然而,從技術上說,catch子句並沒有返回錯誤,它只是返回帶有錯誤信息的結果集。這是非常不同的,因爲它不會導致客戶端代碼中的異常。這就是爲什麼你的結論是正確的,ou應該讓原始錯誤直接傳播回客戶端代碼

正如你所寫,沒有錯誤將被返回給客戶端。如在普通代碼中,如果喲你不要在catch子句中處理(糾正)錯誤,你應該總是在catch子句中重新拋出它(在sql中意味着Raiserror函數)。上面所做的一般情況是不好的,客戶端代碼可能會或可能沒有任何能力來正確處理與預期完全不同的記錄集(一個帶有錯誤信息的記錄集)。某些調用(如插入更新或刪除)可能根本沒有預期或正在查找返回的記錄集......而是,如果您希望或需要在將過程中的錯誤返回給客戶端之前對其進行處理,請使用Raiserror()函數

BEGIN TRY 
    -- Generate divide-by-zero error. 
    SELECT 1/0; 
END TRY 
BEGIN CATCH 
    -- Other code to do logging, whatever ... 
    Raiserror(ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_STATE()) 
END CATCH; 
+0

好的,你已經非常清楚地解釋了..另一個問題:爲什麼你更喜歡在DAL中完成所有這些'捕捉函數'? – 2010-06-10 14:59:35

+0

,因爲通常這些類型的事件(記錄錯誤,儀表,追蹤,操作人員的某些問題的通知等)被稱爲「交叉問題」,可能發生在任何系統模塊中,而不僅僅是數據庫..因此,從整體系統的角度來看,將這種功能置於可從系統中的任何地方訪問的代碼模塊中,而不僅僅是從數據庫中更有意義... – 2010-06-10 15:11:25

+0

如果我想要某個方面導致記錄被保存在數據庫中,我會將該模塊的代碼寫回數據庫作爲它的一個任務... – 2010-06-10 15:12:19

0

不,通過在TRY/CATCH塊中執行Select 1/0,select語句不會返回任何內容,並且catch塊中的select語句將優雅地顯示錯誤詳細信息。查詢成功完成 - 不會引發錯誤。

如果您自己運行Select 1/0,則查詢無法成功完成 - 它會彈出一個錯誤消息。

在SQL中使用catch塊讓你有機會在那裏做一些事情,然後不要讓錯誤冒泡到應用程序。

您看到錯誤細節的唯一原因是因爲您正在選擇它們。如果Catch塊中沒有代碼,則不會看到任何錯誤信息。

1

兩者都返回零除 錯誤。

是的,但使用不同的返回路徑。

區別在於,在第一個示例中,您正在預測錯誤並以某種方式處理它。錯誤作爲常規結果進入應用程序 - 它不會通過錯誤處理機制傳播。事實上,如果應用程序沒有特別看作結果的形狀,那麼它可能不知道發生了錯誤。

在第二個實例中,錯誤通常會通過錯誤報告機制(例如異常)傳播到您的應用程序。這將中止操作。這種影響有多大取決於應用程序的異常處理。也許它會中止當前的操作,或者整個應用程序可能會失敗,這取決於應用程序的設計和對異常的容忍。

您選擇對您的應用有意義的東西。應用程序是否可以有效地處理錯誤 - 如果是這樣,傳播錯誤(第二個示例),或者最好在查詢中處理(第一個示例),並通過返回默認結果(例如空行集)來「平滑」錯誤。

0

使用第一種方法,你不會從SQL Server得到的錯誤直接

第二種方法可以提前

停止它後面

所以最好的語句,你抓住它的執行

1

嘗試抓住是不是有用的,當你所有的嘗試部分是一個選擇。但是,如果您有多個步驟的事務,則使用catch塊將所有步驟回滾並可能記錄有關導致日誌中問題的原因的詳細信息。但最重要的部分是確保數據完整性的回滾。

如果您要在Try塊中創建動態SQl,那麼記錄動態SQl變量失敗並傳入任何參數也會有幫助。這可以幫助解決一些難以捕捉的問題,「我們沒有任何想法是什麼用戶實際上造成的問題「的錯誤。