Como descobrir qual instrução causa erro Msg 3609, Level 16, State 1, Line 4
The transaction ended in the trigger. The batch has been aborted.
?
O código parece bem direto:
-- 1. Check 1
IF (EXISTS (
... check ...
))
BEGIN
RAISERROR('Does not allow 1', 16, 1);
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
RETURN;
END;
-- 2. Check 2
IF (EXISTS (
... check ...
))
BEGIN
RAISERROR('Does not allow 2', 16, 1);
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
RETURN;
END;
Eu verifiquei se a transação existe, então não devo ver esse erro após o erro levantado.
EDITAR:
Concordo com você @gbn. Eu sei que a operação no TRIGGER
é uma transação.
O problema é que no nosso código (escrito por mim e um colega) existe um caso em que RAISERROR
não dispara rollbacks. Vejo isso na prática - o erro é gerado pelo gatilho, mas os novos dados são inseridos. A sintaxe era oposta - primeiro ROLLBACK
e depois RAISERROR
. Descobri que trocar de lugar resolve a situação (não sei por que funciona apenas dessa forma).
Resolvi brincar um pouco com @@TRANCOUNT
. Mas quando inseri vários trancounts, o gatilho começou a me dar 3609. A remoção @@TRANCOUNT
não corrigiu o problema. Pois tenho ROLLBACK
com cheque se existe a transação aberta 3609 é muito estranho para mim. Há outro gatilho, mas mesmo se eu desativá-lo, ainda recebo 3609.
Se você usar TRY/CATCH no código de chamada e no gatilho, o processo de tratamento de erros se tornará muito mais previsível e confiável.
Sem isso, um erro na trigger (aqui causado por RAISERROR) aborta o batch . Portanto, você nunca verá o erro de RAISERROR.
Veja Por que TRY CATCH não suprime a exceção no gatilho para mais
Observação: um gatilho está sempre em uma transação porque faz parte do DML. Qualquer código/ação de gatilho deve ser atômico com o DML, é claro.