sql server:插入事务中的表以记录错误发生?

时间:2011-06-13 07:31:07

标签: sql-server tsql stored-procedures logging transactions

我有一个SP(存储过程),它包含一些T-SQL语句.....

所有T-sql语句都在事务块中,并且通过发生任何错误,我回滚所有事情。

像这样:

BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
         .....
        ......
        IF @@ERROR <>0
        BEGIN
            ROLLBACK TRANSACTION
            RETURN
        END
END
.....
.....

Sp没有正常运行,我找不到它的研究...... 我认为通过将一些数据插入表中来记录sp中的每个操作是个好主意 我的问题是:

因为它使用了一个事务,所以每次插入都会被回滚.....

你有什么看法?还有其他办法吗?

谢谢

4 个答案:

答案 0 :(得分:5)

3件事:
1)如果您不需要,请不要使用游标。
2)您可以使用RAISERROR WITH LOGinserting data into a table variable进行日志记录,然后在回滚事务后将其插入到真实表中。这是可能的,因为表变量是与事务无关的 3)使用try catch

答案 1 :(得分:3)

没有理由现在使用@@ ERROR:TRY / CATCH更可靠。要了解更多,我建议阅读Erland Sommarskog的"Error Handling in SQL 2005 and Later",这是关于该主题的权威文章之一

在这种情况下,没有TRY / CATCH,一些错误是批量中止:这意味着代码停止并且没有错误被捕获。使用TRY / CATCH修复此问题,但编译错误除外。

此模板取自我之前的回答Nested stored procedures containing TRY CATCH ROLLBACK pattern?

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
    -- if desired INSERT ExceptionLogTable () .. 
END CATCH
GO

如果使用SET XACT_ABORT ON(我认为应该是最佳实践),那么在任何CATCH块中@@ trancount为零。因此,除了抛出错误之外,您还可以在此处写入日志记录表。

答案 2 :(得分:1)

我重写了您的代码,使用TransactionTry Catch

为您提供了一个真实的示例
CREATE PROCEDURE [dbo].[mySP] 
(
    @X int, @Y int,
    @Return_Message VARCHAR(1024) = ''  OUT
)
AS

    SET NOCOUNT ON;

    Declare @A varchar(100) @B varchar(100)

BEGIN TRY

    BEGIN TRAN

        IF @X=1
        BEGIN
            declare cu cursor for select col1,col2 from Table1 where Id=@Y
            open  cu
            fetch next from cu into @A, @B
            while  @@Fetch_Status = 0
            BEGIN
                -- .....
                -- do your stuff
                FETCH NEXT FROM cu into @A, @B              
            END
        END

    COMMIT TRAN

    SELECT  @Return_Message = 'All OK'

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 1   -- success

END TRY

BEGIN CATCH
    /*************************************
    *  if errors rollback
    *************************************/
    IF @@TRANCOUNT > 0 ROLLBACK

    SELECT @Return_Message = @ErrorStep + ' '
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '
        + cast(ERROR_LINE() as varchar(20)) + ' ' 
        + ERROR_MESSAGE() + ' > ' 
        + ERROR_PROCEDURE()

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 0   -- fail

END CATCH

SP使用:

declare @ret int, @Return_Message VARCHAR(1024)

EXEC @ret = mySP 1, 2, @Return_Message OUTPUT

-- the SP Fail so print or store the return message with errors ...
if @ret = 0 print @Return_Message

答案 3 :(得分:-2)

您也可以使用Exception Handling来实施Try Catch

Begin Try
    BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
        .....
        ......
        //Your insert statement....
END
.....
.....
Commit Tran

End Try

Begin Catch
      Rollback Tran
      DECLARE @ErrorMessage NVARCHAR(4000);
      DECLARE @ErrorSeverity INT;
      DECLARE @ErrorState INT;

      SELECT @ErrorMessage = ERROR_MESSAGE(),
       @ErrorSeverity = ERROR_SEVERITY(),
       @ErrorState = ERROR_STATE();

      -- Use RAISERROR inside the CATCH block to return 
      -- error information about the original error that 
      -- caused execution to jump to the CATCH block.
      RAISERROR (@ErrorMessage, -- Message text.
           @ErrorSeverity, -- Severity.
           @ErrorState -- State.
           );

End Catch