2012-01-09 43 views
0

在我存儲的特效中,我使用Try-Catch,並在Catch塊中調用一個錯誤處理過程,該過程會將錯誤詳細信息記錄在ErrorLog表中,然後重新拋出錯誤。SQL如何; Try-Catch錯誤信息到錯誤日誌表,用於在事務內執行的存儲過程?

在我的C#代碼,我使用我的執行存儲過程:

using(TransactionScope scope = new TransactionScope()) { 
    // execute stored procs 
    scope.Complete(); 
} 

我遇到的問題,如果交易被中止(scope.Complete不會被調用),我的錯誤處理存儲過程會重新拋出sql錯誤,但不能將錯誤記錄到ErrorLog表中,因爲它位於Transaction的上下文中;有沒有辦法解決 !?我已經知道當事務處於不可提交狀態時無法插入數據,那麼如何退出事務並仍記錄錯誤?

TSQL代碼:

BEGIN PROCEDURE [dbo].[usp_UpsertSomething] 
    @SomethingID BIGINT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    BEGIN TRY 
     -- do something 
    END TRY 
    BEGIN CATCH 
     EXEC dbo.cp_RethrowError 
     RETURN -1 
    END CATCH; 
END 

CREATE PROCEDURE [dbo].[usp_RethrowError] 
    @ErrorLogID [INT] = 0 OUTPUT -- Contains the ErrorLogID of the row inserted 
           -- by cp_RethrowError in the ErrorLog table. 
AS 
BEGIN 
    -- Return if there is no error information to retrieve. 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 

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

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

    -- Build the message string that will contain original 
    -- error information. 
    SELECT @FormattedErrorMessage = 
     'ErrorLogID %d, Error %d, Level %d, State %d, Procedure %s, ' + 
      'Line %d, Message: '+ @ErrorMessage; 

    BEGIN TRY 
     -- Data insertion/modification is not allowed when 
     -- a transaction is in an uncommittable state. 
     IF XACT_STATE() = -1 BEGIN 
      SET @ErrorLogID = 0; 
     END 
     ELSE BEGIN 
      INSERT [dbo].[ErrorLog] 
      (
       ErrorNumber, 
       ErrorSeverity, 
       ErrorState, 
       ErrorProcedure, 
       ErrorLine, 
       ErrorMessage 
      ) 
      VALUES 
      (
       @ErrorNumber, 
       @ErrorSeverity, 
       @ErrorState, 
       @ErrorProcedure, 
       @ErrorLine, 
       @ErrorMessage 
      ); 

      -- Pass back the ErrorLogID of the row inserted 
      SELECT @ErrorLogID = @@IDENTITY; 
     END 
    END TRY 
    BEGIN CATCH 
     PRINT 'An error occurred in stored procedure cp_RethrowError.'; 
    END CATCH 

    -- Raise an error: msg_str parameter of RAISERROR will contain 
    -- the original error information. 
    RAISERROR 
    (
     @FormattedErrorMessage, 
     @ErrorSeverity, 
     1, 
     @ErrorLogID,  -- parameter: ErrorLogID in ErrorLog table. 
     @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. 
    ); 
END 

回答

0

由於交易是全有或全無的交易,來完成唯一的辦法就是我想要做,是調用catch塊內ROLLBACK TRANSACTION,打電話之前我錯誤處理調用。

我的錯誤日誌以我想要記錄的錯誤結束,但是在我的。catch catch塊中,我最終得到了來自SQL的投訴:「EXECUTE後的事務計數表示缺少COMMIT或ROLLBACK TRANSACTION語句。計數= 1,當前計數= 0「。

我可以住在那!

0

您也可以將錯誤日誌條目首先放入一個表變量(它應該與實際日誌表具有相同的結構)。回滾不會清除表變量。最後,你只需要將表變量的內容插入到真實的日誌表中。

我沒有嘗試它,但它可能工作。 SQL Server仍然缺少像自治事務這樣的功能(Oracle已經擁有它)。無論您在自主交易中做什麼,都與主要交易無關。這正是您在錯誤日誌記錄時所需要的:特別是當事務回滾時,您仍然想知道發生了什麼。

0

這是一個排序問題。檢查錯誤處理程序中的事務計數。 步驟: 1.將原始錯誤信息首先存入@variables或@table。 2.檢查您的交易計數,如果它大於0,請將其回滾。 3.插入剛在步驟1中收集的錯誤信息。 完成。