Transação try-catch em Trigger: TSQL

votos
12

Estou tentando colocar uma instrução try-catch dentro de um gatilho usando o Microsoft Server 2005.

BEGIN TRANSACTION
BEGIN TRY
    --Some More SQL
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF (XACT_STATE()) = -1
    BEGIN
        ROLLBACK TRANSACTION;
    END;
END CATCH

O problema é que eu não quero que o gatilho para falhar se algo é capturado pelo bloco try-catch. No momento, eu estou recebendo o erro A operação terminou com o gatilho. O lote foi abortada. se a transação falhar. Como posso obter o gatilho para falhar normalmente?


Além disso, se eu remover a transação, fico com a Operação condenado no gatilho. Batch foi abortada. Erro.

BEGIN TRY
    --Some More SQL
END TRY
BEGIN CATCH
    return
END CATCH

Existe alguma maneira de contornar isso?

Publicado 19/05/2009 em 19:28
fonte usuário
Em outras línguas...                            


9 respostas

votos
8

Na minha experiência, qualquer erro pego em um try catch em um gatilho irá reverter toda a transação; você pode ser capaz de usar uma transação save. Eu acho que você precisa de olhar para o que está acontecendo em "Um pouco mais de sql" e determinar se você pode escrever caso / if em torno dele para parar o erro.

O que você pode ser capaz de tarefas, dependendo do que você está fazendo é usar uma transação salvar e capturar que na captura

Em seu código algo como isto

SAVE TRANSACTION BeforeUpdate;
BEGIN TRY
        --Some More SQL
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION BeforeUpdate;
        return
END CATCH
Respondeu 19/05/2009 em 20:01
fonte usuário

votos
7

Não reverter em um gatilho e não há necessidade de iniciar uma transação também.

O ROLLBACK TRANSACTIONdesfaz o gatilho DML originais e a transação gatilho extra também. Assim, o lote será abortada

Editar:

Eu não sugerir ter um "retorno" em seu bloco de captura e simplesmente permitir que o código para concluir Eu nunca ignorou um erro trapped em um gatilho (mas eu uso try / catch em triggers com reversão e raiserror para re-lance) para esta é uma suposição, mas o retorno é provavelmente uma condição de saída anormal no gatilho

Além disso, tente evitar a condição de erro, em primeiro lugar. Alterar o --some more sqlpara evitar o erro. Exemplo, adicionar if exists(...a testar para uma primeira duplicado ou semelhante

Respondeu 19/05/2009 em 19:32
fonte usuário

votos
2

Use SET XACT_ABORT OFF .Quando Transact-SQL erro declaração encontro, ele só levantou a mensagem de erro ea transação continua o processamento. O código a seguir é criar o gatilho:

Create TRIGGER [dbo].tr_Ins_Table_Master ON [dbo].Table_Master
 AFTER INSERT IGNORE 
AS
BEGIN
set xact_abort off
BEGIN TRY
        --your SQL          
        INSERT IGNORE  INTO Table_Detail
        SELECT MasterID,Name FROM INSERT IGNORE ED

END TRY

BEGIN CATCH     
    select ERROR_MESSAGE()
END CATCH

END
Respondeu 20/04/2017 em 17:25
fonte usuário

votos
2

Para evitar perder os dados transacionais antes da ação de gatilho, você vai querer chamar COMMIT TRAN. Faça isso antes de o bloco try / catch, e você obterá os resultados desejados.

Exemplo:

COMMIT TRAN
BEGIN TRY
    -- possible error occurs here...
END TRY
BEGIN CATCH
    PRINT 'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
    PRINT ERROR_MESSAGE()
END CATCH

Ele irá lançar o seguinte erro ainda - não tenho certeza como evitar:

The transaction ended in the trigger. The batch has been aborted.

Mas tanto a transação original e a transação gatilho deve comprometer com sucesso.

UPDATE: Para evitar a exceção último erro, chamar BEGIN TRAN dentro do try. Nota, a Microsoft recomenda para não chamar COMMIT TRAN dentro de um gatilho, mas se for inevitável, isso deve funcionar para você.

Exemplo:

COMMIT TRAN
BEGIN TRY
    BEGIN TRAN
Respondeu 02/12/2011 em 14:53
fonte usuário

votos
1

Esta demo atinge muitas das coisas feitas acima. mensagens de erro se tornar opcional. O truque que faz o trabalho está em uma dinâmica aninhada executar.

    if object_id('toto')  is not  null drop table toto
    go
    create table toto (i int);
    go
    if object_id('toto2')  is not  null drop table toto2
    go
    create table toto2 (i int);
    go
    create Trigger trtoto
    ON toto
    Instead Of Insert
    as
    Begin
      BEGIN TRY
        set nocount  on
        insert into  toto  values(2)

        declare @sql nvarchar(max) =  'insert into toto2 values(3); select * from ThisTableDoesntexist'

        Exec sp_executeSql N'set xact_abort off; exec (@sql) ', N'@sql nvarchar(max)', @sql

      END TRY

      BEGIN CATCH
        PRINT  'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
        PRINT ERROR_MESSAGE()
      END CATCH
    End

GO
-- tests
set nocount on
insert into toto values (1)  -- is not inserted on purpose by  the trigger
select * from toto   -- other value inserted despite the error
select * from toto2  -- other value inserted in other table despite the error
Respondeu 12/10/2015 em 12:51
fonte usuário

votos
1

não é o melhor caminho, mas ele funciona. Iniciar uma nova transação e fazer a submissão normal rollback e começar outra transação no final, por implícita transação de confirmação

http://msdn.microsoft.com/en-us/library/ms187844(v=SQL.90).aspx

Respondeu 07/12/2011 em 12:36
fonte usuário

votos
1

u07ch,

Infelizmente você não pode usar salvar transação e tentar .. pegar juntos - eles simplesmente não podem trabalhar juntos:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/11/15/avoid-mixing-old-and-new-styles-of-error-handling.aspx

Respondeu 19/05/2009 em 20:57
fonte usuário

votos
0

Você pode definir XACT_ABORT para OFF no início do gatilho.

Respondeu 22/07/2015 em 07:02
fonte usuário

votos
0

Pode ser útil para saber o que você está tentando fazer no gatilho.

O gatilho é parte da transação que enviou os dados para as tabelas inseridas ou excluídas. Se ele falhar, ele irá reverter toda a transação. Se você está esperando o gatilho para falhar ocasionalmente, mas não reverter a afirmação de que casued o gatilho para disparar, em seguida, talvez você precise repensar se um gatilho é a coisa certa para usar.

Respondeu 19/05/2009 em 21:48
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more