Сервер SQL: вставка в таблицу в транзакции для регистрации ошибок? - PullRequest
4 голосов
/ 13 июня 2011

У меня есть 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 ]

5 голосов
/ 13 июня 2011

3 вещи:
1) пожалуйста, не используйте курсоры, если это не нужно.
2) вы можете войти в систему, используя RAISERROR WITH LOG или , вставляя данные в переменную таблицы и затем вставляя их в реальную таблицу после отката транзакции. Это возможно, поскольку переменные таблицы не зависят от транзакций.
3) Используйте try catch block

3 голосов
/ 13 июня 2011

Существует нет причин использовать @@ ERROR сейчас: TRY / CATCH гораздо надежнее. Чтобы понять больше, я рекомендую прочесть книгу Эрланда Соммарскога "Обработка ошибок в SQL 2005 и более поздних версиях" , которая является одной из окончательных статей по этому вопросу

В этом случае без TRY / CATCH некоторые ошибки прерываются пакетно: это означает, что код останавливается и ошибка не перехватывается. Это исправлено TRY / CATCH за исключением ошибок компиляции.

Этот шаблон взят из моего предыдущего ответа Вложенные хранимые процедуры, содержащие шаблон TRY CATCH ROLLBACK?

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 равен нулю. Так что вы можете записать в таблицу регистрации здесь, если хотите, в дополнение к выдаче ошибки.

1 голос
/ 13 июня 2011

Я переписал ваш код, чтобы дать вам реальный пример, используя Transaction и Try 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
0 голосов
/ 13 июня 2011

Вы также можете реализовать Обработка исключений , используя Попробуйте также 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
...