Reversões e confirmações em procedimentos armazenados e disparadores

É possível executar uma instrução Transact-SQL ROLLBACK TRANSACTION ou COMMIT TRANSACTION em um procedimento armazenado ou disparador, mas isso pode causar erros.

Em procedimentos armazenados

Se @@TRANCOUNT tiver um valor diferente quando um procedimento armazenado for concluído do que tinha quando o procedimento foi executado, ocorrerá um erro informativo (266). Isso pode acontecer de dois modos:

  • Um procedimento armazenado é chamado com um @@TRANCOUNT de 1 ou maior e o procedimento armazenado executa uma instrução ROLLBACK TRANSACTION. @@TRANCOUNT diminui a 0 e causa um erro 266 quando o procedimento armazenado é concluído.

  • Um procedimento armazenado é chamado com um @@TRANCOUNT de 1 ou maior e o procedimento armazenado executa uma instrução COMMIT TRANSACTION. @@TRANCOUNT diminui em 1 e causa um erro 266 quando o procedimento armazenado é concluído. Porém, se for executado BEGIN TRANSACTION depois de COMMIT TRANSACTION, o erro não acontecerá.

Em disparadores

Um disparador funciona como se ocorresse uma transação pendente quando o disparador é executado. Isso é verdadeiro se a instrução que aciona o disparador estiver em uma transação implícita ou explícita.

Quando uma instrução é iniciada no modo de autoconfirmação, haverá um BEGIN TRANSACTION implícito para permitir a recuperação de todas as modificações geradas pela instrução, caso ela encontre um erro. Essa transação implícita não tem nenhum efeito nas outras instruções no lote porque estará comprometida ou revertida quando a instrução for concluída. Entretanto, quando um disparador for chamado, essa transação implícita ainda estará ativa.

Quando um disparador é acionado, uma transação implícita é iniciada. Se o gatilho concluir a execução e um @@TRANCOUNT = 0, ocorrerá um erro 3609 e o lote será finalizado. Se uma instrução BEGIN TRANSACTION for emitida em um gatilho, ela criará uma transação aninhada. Nessa situação, quando uma instrução COMMIT TRANSACTION é executada, ela se aplica somente à transação aninhada.

Ao utilizar ROLLBACK TRANSACTION em um disparador, tenha em mente o seguinte comportamento:

  • Todas as modificações de dados feitas até aquele ponto na transação atual são revertidas, inclusive qualquer uma que tenha sido feita pelo disparador.

  • O disparador continua executando qualquer instrução restante depois da instrução ROLLBACK. Se alguma dessas instruções modificar dados, as modificações não serão revertidas.

  • Um ROLLBACK em um disparador fecha e desaloca todos os cursores que foram declarados e abertos no lote que contém a instrução que acionou o disparador. Isso inclui cursores declarados e abertos em procedimentos armazenados chamados pelo lote que acionou o disparador. Os cursores declarados em um lote anterior ao lote que acionou o disparador estão apenas fechados. Porém, os cursores STATIC ou INSENSITIVE são mantidos abertos:

    • CURSOR_CLOSE_ON_COMMIT está definido como OFF.

    • O cursor estático é um cursor síncrono ou assíncrono totalmente populado.

Ao invés de utilizar ROLLBACK TRANSACTION, poderá ser utilizada a instrução SAVE TRANSACTION para executar uma reversão parcial em um disparador.