Qual é a vantagem de usar "SET XACT_ABORT ON" em um procedimento armazenado?

Respostas:

231

SET XACT_ABORT ONinstrui o SQL Server a reverter toda a transação e abortar o lote quando ocorrer um erro em tempo de execução. Ele cobre você em casos como um tempo limite de comando que ocorre no aplicativo cliente, e não no próprio SQL Server (que não é coberto pela XACT_ABORT OFFconfiguração padrão ).

Como o tempo limite da consulta deixará a transação aberta, SET XACT_ABORT ONé recomendado em todos os procedimentos armazenados com transações explícitas (a menos que você tenha um motivo específico para fazer outra coisa), pois as conseqüências de um aplicativo que executa o trabalho em uma conexão com uma transação aberta são desastrosas.

Há uma excelente visão geral no blog de Dan Guzman ,

Ben Griswold
fonte
41
então por que não está ativado por padrão?
Mike W
1
O XACT_ABORT ainda é necessário se você tiver o BEGIN TRY- BEGIN CATCHe ROLLBACKcom o BEGIN CATCHbloco no Sql?
user20358
1
@ user20358 BEGIN TRY- BEGIN CATCHnão captura coisas como um tempo limite no aplicativo cliente, e alguns erros SQL também são impossíveis de rastrear , deixando uma transação aberta em que você não esperaria uma.
Tom Lint
37

Na minha opinião, SET XACT_ABORT ON foi tornado obsoleto pela adição de BEGIN TRY / BEGIN CATCH no SQL 2k5. Antes dos blocos de exceção no Transact-SQL, era realmente difícil lidar com erros e os procedimentos desequilibrados eram muito comuns (procedimentos que tinham uma @@ TRANCOUNT diferente na saída em comparação à entrada).

Com a adição do tratamento de exceção Transact-SQL, é muito mais fácil escrever procedimentos corretos que garantem o equilíbrio adequado das transações. Por exemplo, eu uso este modelo para manipulação de exceção e transações aninhadas :

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go

Isso me permite escrever procedimentos atômicos que revertem apenas seu próprio trabalho em caso de erros recuperáveis.

Um dos principais problemas enfrentados pelos procedimentos Transact-SQL é a pureza dos dados : algumas vezes, os parâmetros recebidos ou os dados nas tabelas estão completamente errados, resultando em erros de chave duplicados, erros de restrição referenciais, erros de verificação de restrição e assim por diante. Afinal, esse é exatamente o papel dessas restrições, se esses erros de pureza dos dados fossem impossíveis e todos capturados pela lógica de negócios, as restrições seriam todas obsoletas (exagero dramático adicionado para efeito). Se XACT_ABORT estiver ativado, todos esses erros resultarão na perda de toda a transação, em vez de poder codificar blocos de exceção que manipulam a exceção normalmente. Um exemplo típico é tentar fazer um INSERT e reverter para uma violação UPDATE on PK.

Remus Rusanu
fonte
9
Exceto pelo tempo limite do cliente ... e, na minha opinião, o SET XACT_ABORT é mais eficaz no SQL 2005 porque o comportamento é mais previsível: muito menos erros de interrupção de lote.
gbn 19/07/2009
7
Concordo um pouco, mas planejo meu tratamento de erros em todas as eventualidades, porque sei que serei responsável pelo DBA do desenvolvedor se ocorrer um tempo limite de comando.
gbn
4
@RemusRusanu De que outra forma você lidaria com uma operação de banco de dados síncrona e de longa execução?
22813 Ian Boyd
5
A documentação do MSDN afirma: "XACT_ABORT deve estar ativado para instruções de modificação de dados em uma transação implícita ou explícita na maioria dos provedores OLE DB, incluindo o SQL Server. O único caso em que essa opção não é necessária é se o provedor oferecer suporte a transações aninhadas." msdn.microsoft.com/pt-BR/library/ms188792(v=sql.120).aspx
Nathan
4
"Na minha opinião, SET XACT_ABORT ON ficou obsoleto com a adição de BEGIN TRY / BEGIN CATCH" - Estou ouvindo, mas consulte sommarskog.se/error_handling/Part1.html
Engineer
22

Citando o MSDN :

Quando SET XACT_ABORT está ativado, se uma instrução Transact-SQL gerar um erro em tempo de execução, a transação inteira será encerrada e revertida. Quando SET XACT_ABORT está desativado, em alguns casos, apenas a instrução Transact-SQL que gerou o erro é revertida e a transação continua o processamento.

Na prática, isso significa que algumas das instruções podem falhar, deixando a transação 'parcialmente concluída', e pode não haver sinal dessa falha para um chamador.

Um exemplo simples:

INSERT INTO t1 VALUES (1/0)    
INSERT INTO t2 VALUES (1/1)    
SELECT 'Everything is fine'

Esse código seria executado 'com êxito' com XACT_ABORT OFF e terminará com um erro com XACT_ABORT ON ('INSERT INTO t2' não será executado e um aplicativo cliente gerará uma exceção).

Como uma abordagem mais flexível, você pode verificar @@ ERROR após cada instrução (old school) ou usar os blocos TRY ... CATCH (MSSQL2005 +). Pessoalmente, prefiro definir XACT_ABORT ON sempre que não houver motivo para algum tratamento avançado de erros.

VladV
fonte
8

Com relação aos tempos limite do cliente e ao uso de XACT_ABORT para manipulá-los, na minha opinião, há pelo menos um motivo muito bom para ter tempos limites nas APIs do cliente, como SqlClient, e que é para proteger o código do aplicativo cliente contra conflitos que ocorrem no código do servidor SQL. Nesse caso, o código do cliente não tem falhas, mas deve se proteger de um bloqueio permanente, aguardando a conclusão do comando no servidor. Por outro lado, se houver um tempo limite do cliente para proteger o código do cliente, o XACT_ABORT ON precisará proteger o código do servidor contra as interrupções do cliente, caso o código do servidor demore mais para ser executado do que o cliente está disposto a esperar.

ionutm
fonte
1

É usado no gerenciamento de transações para garantir que quaisquer erros resultem na reversão da transação.

Dan Diplo
fonte