2016-05-06 104 views
6

我是一位學習更多TSQL的c#開發人員。我寫了一個這樣的腳本:交易是否需要嘗試追蹤?

begin transaction 
--Insert into several tables 
end transaction 

但有人告訴我,這不是一個好主意,用這樣的:

BEGIN TRANSACTION; 

BEGIN TRY 
    -- Generate a constraint violation error. 
    DELETE FROM Production.Product 
    WHERE ProductID = 980; 
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; 

    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION; 
END CATCH; 

IF @@TRANCOUNT > 0 
    COMMIT TRANSACTION; 
GO 

我不明白爲什麼第二個例子是比較正確的。第一個會不會以同樣的方式工作?看起來第一個會更新所有的表格,或者根本沒有?我不明白爲什麼在提交之前檢查@@TRANCOUNT是必要的。

+1

我會作出相同的論點,你是。另外,推薦給你的try/catch模式是一種反模式,我稱之爲try/squelch。它捕獲和錯誤,然後默默地進行。這不是處理錯誤,它是壓制他們。這就是說,一個事務不需要try/catch塊。特別是如果你處於觸發狀態,使用try/catch可能會導致比以往更多的問題。 –

+2

如果在第二個例子中有任何事情,提交應該在try塊中,而不是在catch之後......我認爲 – Kritner

回答

4

只有當您處於try塊中並且在實際語句之前時纔打開一個事務,並立即提交,不要等到您的控件轉到批處理的末尾來提交事務。

一旦進入Try Block並且您已經打開了一個事務,如果出現問題控制將跳轉到CATCH塊,只需在那裏回滾您的事務並根據需要執行其他錯誤處理。

在使用@@ ROWCOUNT函數實際回滾事務檢查之前,我已經添加了一點檢查,它在這種情況下確實沒有多大意義。當你在你的try塊中進行一些驗證檢查時,如果任何驗證檢查失敗,在你打開一個事務,比如檢查參數值和其他東西,並在try塊中產生錯誤之前,它會更有用。在這種情況下,控制將跳轉到catch塊如果沒有打開交易,那麼您可以檢查是否有任何打開的交易,如果有開放的交易則回滾。就您的情況而言,您實際上不需要檢查任何未清交易,因爲除非您的交易中出現問題,否則您將不會觸發catch塊。

BEGIN TRY 

    BEGIN TRANSACTION 
    -- Multiple Inserts 
    INSERT INTO.... 
    INSERT INTO.... 
    INSERT INTO.... 
COMMIT TRANSACTION 
    PRINT 'Rows inserted successfully...' 

END TRY 

BEGIN CATCH 
    IF (@@TRANCOUNT > 0) 
    BEGIN 
     ROLLBACK TRANSACTION 
     PRINT 'Error detected, all changes reversed' 
    END 
    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 
+0

我認爲你的解釋中是'@@ TranCount',而不是'@@ RowCount'。我還不願意在一個普通的信息中包含「所有變化逆轉」,因爲可能存在「丟失」的身份值,由觸發引起的副作用......。 – HABO

0

我在T-SQL中關於TRY ... CATCH的兩個想法。

雖然它對語言來說是一種潛在的有用補充,但它可用的事實並不總是使用它的理由。

以你

DELETE FROM Table WHERE... 

例子(我知道僅僅是一個例子)。唯一會失敗的方式是出現錯誤,如果代碼嚴重受限於模式。 (例如,如果某人在PK端使用Table創建了一個外鍵)。

經過適當的測試,代碼和模式之間的這種不匹配不應該使其投入生產。假設它確實如此,恕我直言,「粗魯」的,未中介的錯誤信息將會比「有禮貌地」將其包裝到SELECT語句中以返回客戶端更好地指出發生了什麼問題。 (這可以相當於嘗試/禁止反模式SeanLange提到)。

對於更復雜的場景,我可以看到TRY ... CATCH的用法。雖然恕我直言,它不能替代仔細驗證輸入參數。

1

我想在這裏給我的觀點作爲一個C#開發人員:

在上述第(剛插入從腳本幾桌)給出的簡單的情況下,沒有理由加一個try/catch,如它對交易沒有任何好處。這兩個例子都會產生完全相同的結果:所有表都將被插入,否則它們將不會被插入。數據庫的狀態保持一致。(由於COMMIT TRANSACTION從未被調用,回滾在腳本結尾處由Sql Server隱式調用)。

但是,有時您可以在try/catch中執行集成不可能實現的功能錯誤處理。例如,將錯誤記錄到錯誤表中。

在我的C#經驗中,使用Try/Catch的唯一時間是當開發人員控制之外有某些東西,比如試圖打開文件。在這種情況下,管理由.Net框架生成的異常的唯一方法是通過Try/Catch。

如果我正在做一個存儲過程,並想手動檢查數據的狀態並手動調用ROLLBACK TRANSACTION,我可以看到。但它仍然不需要嘗試/捕獲。