Quali sono i vantaggi dell'utilizzo di "SET XACT_ABORT ON" in una procedura memorizzata?


Risposte:


231

SET XACT_ABORT ONindica a SQL Server di eseguire il rollback dell'intera transazione e di interrompere il batch quando si verifica un errore di runtime. Ti copre in casi come un timeout del comando che si verifica sull'applicazione client piuttosto che all'interno dello stesso SQL Server (che non è coperto dall'impostazione predefinita XACT_ABORT OFF).

Poiché un timeout della query lascerà aperta la transazione, SET XACT_ABORT ONè consigliabile in tutte le procedure memorizzate con transazioni esplicite (a meno che non si abbia un motivo specifico per fare diversamente) poiché le conseguenze di un'applicazione che esegue un lavoro su una connessione con una transazione aperta sono disastrose.

C'è una fantastica panoramica sul blog di Dan Guzman ,


41
quindi perché non è attivo per impostazione predefinita?
Mike W,

1
XACT_ABORT è ancora richiesto se hai il BEGIN TRY- BEGIN CATCHe ROLLBACKcon il BEGIN CATCHblocco in Sql?
user20358

1
@ user20358 BEGIN TRY- BEGIN CATCHnon rileverà cose come un timeout che si verifica nell'applicazione client e anche alcuni errori SQL sono irraggiungibili, lasciandoti con una transazione aperta dove non te lo aspetti.
Tom Lint,

37

A mio avviso, SET XACT_ABORT ON è stato reso obsoleto dall'aggiunta di BEGIN TRY / BEGIN CATCH in SQL 2k5. Prima dei blocchi delle eccezioni in Transact-SQL era davvero difficile gestire gli errori e le procedure sbilanciate erano fin troppo comuni (procedure che avevano un @@ TRANCOUNT diverso all'uscita rispetto all'entrata).

Con l'aggiunta della gestione delle eccezioni Transact-SQL è molto più semplice scrivere le procedure corrette che garantiscono il corretto bilanciamento delle transazioni. Ad esempio, utilizzo questo modello per la gestione delle eccezioni e le transazioni nidificate :

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

Mi permette di scrivere procedure atomiche che eseguano il rollback solo del proprio lavoro in caso di errori recuperabili.

Uno dei problemi principali affrontati dalle procedure Transact-SQL è la purezza dei dati : a volte i parametri ricevuti o i dati nelle tabelle sono semplicemente errati, con conseguenti errori chiave duplicati, errori di vincolo referenziale, errori di vincolo di controllo e così via e così via. Dopotutto, questo è esattamente il ruolo di questi vincoli, se questi errori di purezza dei dati sarebbero impossibili e tutti catturati dalla logica aziendale, i vincoli sarebbero tutti obsoleti (drammatica esagerazione aggiunta per effetto). Se XACT_ABORT è ON, tutti questi errori comportano la perdita dell'intera transazione, anziché essere in grado di codificare i blocchi di eccezioni che gestiscono l'eccezione con grazia. Un esempio tipico è il tentativo di eseguire un INSERT e il ripristino di un UPDATE su violazione PK.


9
Tranne i timeout dei client ... e la mia opinione è che SET XACT_ABORT è più efficace in SQL 2005 perché il comportamento è più prevedibile: molti meno errori di interruzione batch.
gbn

7
Sono un po 'd'accordo, ma pianifico la mia gestione degli errori su tutte le eventualità, perché so che avrò la colpa come DBA sviluppatore se si verifica un timeout del comando.
gbn

4
@RemusRusanu In quale altro modo gestiresti un'operazione di database sincrona e di lunga durata?
Ian Boyd,

5
La documentazione MSDN afferma: "XACT_ABORT deve essere impostato su ON per le dichiarazioni di modifica dei dati in una transazione implicita o esplicita contro la maggior parte dei provider OLE DB, incluso SQL Server. L'unico caso in cui questa opzione non è richiesta è se il provider supporta transazioni nidificate". msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Nathan

4
"Secondo me SET XACT_ABORT ON è stato reso obsoleto dall'aggiunta di BEGIN TRY / BEGIN CATCH" - Ti sento bene, ma per favore vedi sommarskog.se/error_handling/Part1.html
Ingegnere invertito

22

Citando MSDN :

Quando SET XACT_ABORT è ON, se un'istruzione Transact-SQL genera un errore di runtime, l'intera transazione viene terminata e ripristinata. Quando SET XACT_ABORT è OFF, in alcuni casi viene eseguito il rollback solo dell'istruzione Transact-SQL che ha generato l'errore e la transazione continua l'elaborazione.

In pratica ciò significa che alcune delle dichiarazioni potrebbero non riuscire, lasciando la transazione "parzialmente completata" e potrebbe non esserci alcun segno di questo errore per un chiamante.

Un semplice esempio:

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

Questo codice verrebbe eseguito "correttamente" con XACT_ABORT OFF e terminerà con un errore con XACT_ABORT ON ("INSERT INTO t2" non verrà eseguito e un'applicazione client genererà un'eccezione).

Come approccio più flessibile, è possibile controllare @@ ERROR dopo ogni istruzione (vecchia scuola) o utilizzare i blocchi TRY ... CATCH (MSSQL2005 +). Personalmente preferisco impostare XACT_ABORT ON ogni volta che non vi è alcun motivo per una gestione avanzata degli errori.


8

Per quanto riguarda i timeout dei client e l'uso di XACT_ABORT per gestirli, secondo me c'è almeno un ottimo motivo per avere timeout nelle API client come SqlClient, e cioè proteggere il codice dell'applicazione client dai deadlock che si verificano nel codice del server SQL. In questo caso il codice client non ha alcun difetto, ma deve proteggersi dal blocco per sempre in attesa del completamento del comando sul server. Quindi, al contrario, se devono esistere timeout del client per proteggere il codice client, così XACT_ABORT ON deve proteggere il codice del server dalle interruzioni del client, nel caso in cui il codice del server impieghi più tempo per l'esecuzione di quanto il client è disposto ad aspettare.


1

Viene utilizzato nella gestione delle transazioni per garantire che qualsiasi errore comporti il ​​rollback della transazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.