2012-01-09 45 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中收集的错误信息。 完成。