2014-01-22 90 views
2

我的同事有這樣一個過程:SQL Server 2008 R2的交易是@@ ERROR必要的,是ROLLBACK TRANS必要

BEGIN TRAN 
--Some deletes and inserts 
IF(@@error <> 0) 
BEGIN 
    ROLLBACK TRAN 
    RETURN 
END 
COMMIT TRAN 

我有另一個在一個存儲過程,簡單地說就是:

BEGIN TRANSACTION 
    --Some deltes and inserts 
COMMIT TRANSACTION 

我已經測試並發現我的過程在錯誤期間總是將所有內容都回滾(例如,更改列數據類型等進行測試),而無需顯式編碼回滾。此外,我已閱讀使用@@error條件已過時的SQL Server 2005及以上。

你會說什麼是SQL Server 2008 R2及更高版本的事務的正確方法?謝謝

回答

12

是的ROLLBACK是必要的!

我會做基於此模板的SQL Server 2005和更新的存儲過程:

BEGIN TRANSACTION 
BEGIN TRY 

    -- put your T-SQL commands here  

    -- if successful - COMMIT the work 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    -- handle the error case (here by displaying the error) 
    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 

    -- in case of an error, ROLLBACK the transaction  
    ROLLBACK TRANSACTION 

    -- if you want to log this error info into an error table - do it here 
    -- *AFTER* the ROLLBACK 
END CATCH 
+4

+1只是一個註釋,你應該在回滾之後執行log *,否則你會回滾寫入日誌表。 :-) –

+0

@AaronBertrand:好點! :-)我從來沒有覺得有必要將錯誤記錄到表中 - 但你絕對正確 –

+1

「處理錯誤情況」如果你不想在SQL中處理它,該怎麼辦?我幾乎總是希望將例外發送到應用程序。我認爲我非常希望將異常信息作爲結果集。甚至很難檢測到這樣的結果集。我需要查看列名。 – usr

0

在你的數據庫中創建下列程序然後在catch塊,只需exec RethrowError。 關於這樣做的好處是,你沒有任何參數傳遞到它從你的主存儲過程

CREATE PROCEDURE [dbo].[RethrowError] AS 
-- Return if there is no error information to retrieve. 
IF ERROR_NUMBER() IS NULL 
    RETURN; 

DECLARE 
    @ErrorMessage NVARCHAR(4000), 
    @ErrorNumber  INT, 
    @ErrorSeverity INT, 
    @ErrorState  INT, 
    @ErrorLine  INT, 
    @ErrorProcedure NVARCHAR(200); 

-- Assign variables to error-handling functions that 
-- capture information for RAISERROR. 
SELECT 
    @ErrorNumber = ERROR_NUMBER(), 
    @ErrorSeverity = ERROR_SEVERITY(), 
    @ErrorState = ERROR_STATE(), 
    @ErrorLine = ERROR_LINE(), 
    @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-'); 

-- Building the message string that will contain original 
-- error information. 
SELECT @ErrorMessage = 
    N'Error %d, Level %d, State %d, %s, Line %d' + ERROR_MESSAGE(); 

-- Raise an error: msg_str parameter of RAISERROR will contain 
-- the original error information. 
RAISERROR 
    (
    @ErrorMessage, 
    @ErrorSeverity, 
    1,    
    @ErrorNumber, -- parameter: original error number. 
    @ErrorSeverity, -- parameter: original error severity. 
    @ErrorState,  -- parameter: original error state. 
    @ErrorProcedure, -- parameter: original error procedure name. 
    @ErrorLine  -- parameter: original error line number. 
    ); 


GO 

CREATE PROCEDURE YourProcedure 

AS 

BEGIN TRANSACTION 

BEGIN TRY 

--Put your code in here 


END TRY 


BEGIN CATCH 

EXEC RethrowError 

END CATCH 


END 
+0

這當然有效,因爲我這樣使用RAISERROR的問題是,它將錯誤編號更改爲50000,這使得客戶端無法使用標準方法來檢查錯誤代碼。如果您使用的是SQL2012 plus,那麼您可以在CATCH塊中簡單地使用THROW而不使用參數。 – knightpfhor

4

有一個問題與@@ ERROR變量。 這是一個全局變量,因此,如果你正在做的事情,如:

BEGIN TRAN 

    --inserts 
    --deletes 
    --updates 
    -- last operation 

IF(@@error <> 0) 
BEGIN 
    ROLLBACK TRAN 
    RETURN 
END 
COMMIT TRAN 

@@ ERROR只包含對最後的操作結果。因此這段代碼可以掩蓋以前操作​​中的錯誤。

我的建議是,如果您可以在應用程序級別管理事務,則在應用程序級別執行此操作。 在服務器端處理錯誤不適用於微弱的心靈,它不會提高您的應用程序的魯棒性。