2011-02-14 91 views
7

我遇到一個存儲過程,在更新嘗試後立即有以下錯誤處理塊。以下是SP的最後一行。T-SQL中的TRY CATCH塊

這樣做有什麼好處嗎?在我看來,好像這個代碼只是重新拋出沒有任何附加價值而被捕獲的同樣的錯誤,並且如果Try Block完全被忽略,代碼可能會表現爲100%。

如果TRY塊被省略,那麼結果SP的行爲會有什麼不同嗎?

BEGIN CATCH 

SELECT @ErrMsg = ERROR_MESSAGE(), @ErrSev = ERROR_SEVERITY(), @ErrState = ERROR_STATE() 
     RAISERROR (@ErrMsg, @ErrSev, @ErrState) 

END CATCH 
+0

我能想到的唯一區別是,行號信息和錯誤號碼信息會更準確,因爲沒有`CATCH`拋出一個新的異常,所以它實際上似乎減去了值,據我所知。 .. – 2011-02-14 14:44:41

+0

我總是喜歡在前端有一個自定義的錯誤消息,而不是sql生成的錯誤消息。這種方式會給你你理解和提到的邏輯和技術錯誤。 – Chris 2011-02-14 15:08:48

回答

2

除非返回的任何消息部分出現「線路錯誤」,否則會引用RAISERROR行而不是錯誤實際發生的行,則不會有任何區別。做這件事的主要原因是@Chris說,讓您以編程方式使用/操作錯誤數據。

2

我們通常在我們的存儲過程做的是寫catch塊這樣

BEGIN CATCH 
    DECLARE @i_intErrorNo int   
    DECLARE @i_strErrorMsg nvarchar(1000)   
    DECLARE @i_strErrorProc nvarchar(1000)   
    DECLARE @i_intErrorLine int   

    SELECT @i_intErrorNo=Error_Number()   
    SELECT @i_strErrorMsg=Error_Message()   
    SELECT @i_strErrorProc=Error_Procedure()   
    SELECT @i_intErrorLine=Error_Line() 

    INSERT INTO error table ////// Insert statement. 

END CATCH 

這是我們用來做存儲錯誤的東西。爲了給用戶正確的消息,我總是使用輸出參數來存儲過程來顯示錯誤的詳細/必需的原因。

1

如果你看一下在msdn page for RAISERROR然後就看到這個一般描述:

生成錯誤消息和 啓動錯誤處理的 會議。 RAISERROR可以或者 引用存儲在sys.messages目錄 視圖中的用戶定義消息 或動態構建消息。 該消息作爲服務器 錯誤消息返回給調用的 應用程序或TRY ... CATCH構造的關聯CATCH 塊。

看起來「調用應用程序」會出現錯誤信息。這可能是存儲過程的創建者只需要報告錯誤消息,嚴重性和狀態,並且不能添加其他選項。這可能是由於安全問題,或者是由於調用應用程序不需要知道額外的信息(可能是冗長或過於詳細的)。

+0

所有「額外信息」都包含在由ERROR_MESSAGE()返回的字符串中。混淆這一點,你必須用你自己的更少的消息來替換它,這個例程不會這樣做。 – 2011-02-14 14:50:38

0

存在一個細微的差異,如下所示。

首次設置如下:

CREATE TABLE TMP 
(ROW_ID int NOT NULL, 
    ALTER TABLE TMP ADD CONSTRAINT PK_TMP PRIMARY KEY CLUSTERED (ROW_ID) 
) 
GO 
CREATE PROC pTMP1 
AS 
BEGIN TRY 
    INSERT INTO TMP VALUES(1) 
    INSERT INTO TMP VALUES(1) 
    INSERT INTO TMP VALUES(2) 
END TRY 
BEGIN CATCH 
    DECLARE @ErrMsg varchar(max)= ERROR_MESSAGE(), 
      @ErrSev int = ERROR_SEVERITY(), 
      @ErrState int = ERROR_STATE() 
     RAISERROR (@ErrMsg, @ErrSev, @ErrState) 
END CATCH 
GO 
CREATE PROC pTMP2 
AS 
    INSERT INTO TMP VALUES(1) 
    INSERT INTO TMP VALUES(1) 
    INSERT INTO TMP VALUES(2) 
GO 

現在運行以下命令:

SET NOCOUNT ON 
DELETE TMP 
exec pTMP1 
SELECT * FROM TMP 
DELETE TMP 
exec pTMP2 
SELECT * FROM TMP 
SET NOCOUNT OFF 
--Cleanup 
DROP PROCEDURE pTMP1 
DROP PROCEDURE pTMP2 
DROP TABLE TMP 

你應該得到以下結果:

Msg 50000, Level 14, State 1, Procedure pTMP1, Line 12 
Violation of PRIMARY KEY constraint 'PK_TMP'. Cannot insert duplicate key in object 'dbo.TMP'. The duplicate key value is (1). 
ROW_ID 
----------- 
1 

Msg 2627, Level 14, State 1, Procedure pTMP2, Line 4 
Violation of PRIMARY KEY constraint 'PK_TMP'. Cannot insert duplicate key in object 'dbo.TMP'. The duplicate key value is (1). 
The statement has been terminated. 
ROW_ID 
----------- 
1 
2 

注意,TRY..CATCH版本沒有執行第三個INSERT聲明,而pTMP2 proc沒有。這是因爲一旦發生錯誤,控制就跳轉到CATCH

注意:pTMP2的行爲受XACT_ABORT設置的影響。

結論

使用TRY..CATCH所證實的好處取決於你如何管理自己的事務邊界。

  • 如果您回滾任何錯誤,則更改將被撤消。但是這並不能消除附加處理等副作用。注意:如果不同的會話使用WITH(NOLOCK)同時查詢TMP,它甚至可能會觀察到臨時更改。
  • 但是,如果您不打算回滾事務,則可能會發現該技術對於防止應用某些數據更改(儘管存在較早的錯誤)非常重要。