Was ist der Vorteil der Verwendung von "SET XACT_ABORT ON" in einer gespeicherten Prozedur?

Antworten:

231

SET XACT_ABORT ONWeist SQL Server an, die gesamte Transaktion zurückzusetzen und den Stapel abzubrechen, wenn ein Laufzeitfehler auftritt. Es behandelt Sie in Fällen wie einem Befehlszeitlimit, das in der Clientanwendung und nicht in SQL Server selbst auftritt (was nicht durch die Standardeinstellung abgedeckt ist XACT_ABORT OFF).

Da ein Abfragezeitlimit die Transaktion offen lässt, SET XACT_ABORT ONwird dies in allen gespeicherten Prozeduren mit expliziten Transaktionen empfohlen (sofern Sie keinen bestimmten Grund haben, etwas anderes zu tun), da die Folgen einer Anwendung, die Arbeiten an einer Verbindung mit einer offenen Transaktion ausführt, katastrophal sind.

Es gibt einen wirklich guten Überblick auf Dan Guzmans Blog ,

Ben Griswold
quelle
41
Warum ist es nicht standardmäßig eingeschaltet?
Mike W
1
Wird XACT_ABORT noch benötigt, wenn Sie das BEGIN TRY- BEGIN CATCHund ROLLBACKmit dem BEGIN CATCHBlock in SQL haben?
user20358
1
@ user20358 BEGIN TRY- Fängt BEGIN CATCHkeine Zeitüberschreitungen in der Clientanwendung ab, und einige SQL-Fehler sind auch nicht abfangbar, sodass Sie eine offene Transaktion haben, bei der Sie keine erwarten würden.
Tom Lint
37

Meiner Meinung nach wurde SET XACT_ABORT ON durch das Hinzufügen von BEGIN TRY / BEGIN CATCH in SQL 2k5 überholt. Vor Ausnahmeblöcken in Transact-SQL war es wirklich schwierig, Fehler zu behandeln, und unausgeglichene Prozeduren waren allzu häufig (Prozeduren, die beim Beenden ein anderes @@ TRANCOUNT hatten als beim Eintritt).

Mit der Hinzufügung von Transact-SQL ist die Ausnahmebehandlung viel einfacher, korrekte Prozeduren zu schreiben, die garantiert einen ordnungsgemäßen Ausgleich der Transaktionen gewährleisten. Zum Beispiel verwende ich diese Vorlage für die Ausnahmebehandlung und verschachtelte Transaktionen :

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

Es ermöglicht mir, atomare Prozeduren zu schreiben, die bei behebbaren Fehlern nur ihre eigene Arbeit zurücksetzen.

Eines der Hauptprobleme bei Transact-SQL-Prozeduren ist die Datenreinheit : Manchmal sind die empfangenen Parameter oder die Daten in den Tabellen einfach falsch, was zu doppelten Schlüsselfehlern, referenziellen Einschränkungsfehlern, Überprüfungsbeschränkungsfehlern usw. führt. Schließlich ist dies genau die Rolle dieser Einschränkungen. Wenn diese Datenreinheitsfehler unmöglich wären und alle von der Geschäftslogik erfasst würden, wären die Einschränkungen veraltet (dramatische Übertreibung für den Effekt hinzugefügt). Wenn XACT_ABORT aktiviert ist, gehen all diese Fehler dazu, dass die gesamte Transaktion verloren geht, anstatt Ausnahmeblöcke codieren zu können, die die Ausnahme ordnungsgemäß behandeln. Ein typisches Beispiel ist der Versuch, ein INSERT durchzuführen und bei einer PK-Verletzung zu einem UPDATE zurückzukehren.

Remus Rusanu
quelle
9
Mit Ausnahme von Client-Timeouts ... und meiner Ansicht nach ist SET XACT_ABORT in SQL 2005 effektiver, da das Verhalten vorhersehbarer ist: weitaus weniger Fehler beim Batch-Abbruch.
Gbn
7
Ich stimme etwas zu, aber ich plane meine Fehlerbehandlung unter Berücksichtigung aller Eventualitäten, da ich weiß, dass ich als Entwickler-DBA die Schuld dafür bekomme, wenn ein Befehls-Timeout auftritt.
gbn
4
@RemusRusanu Wie würden Sie sonst mit einer lang laufenden, synchronen Datenbankoperation umgehen?
Ian Boyd
5
In der MSDN-Dokumentation heißt es: "XACT_ABORT muss für Datenänderungsanweisungen in einer impliziten oder expliziten Transaktion für die meisten OLE DB-Anbieter, einschließlich SQL Server, aktiviert sein. Diese Option ist nur erforderlich, wenn der Anbieter verschachtelte Transaktionen unterstützt." msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Nathan
4
"Meiner Meinung nach wurde SET XACT_ABORT ON durch das Hinzufügen von BEGIN TRY / BEGIN CATCH überholt." - Ich höre Sie, aber siehe sommarskog.se/error_handling/Part1.html
Reversed Engineer
22

MSDN zitieren :

Wenn SET XACT_ABORT aktiviert ist und eine Transact-SQL-Anweisung einen Laufzeitfehler auslöst, wird die gesamte Transaktion beendet und zurückgesetzt. Wenn SET XACT_ABORT auf OFF gesetzt ist, wird in einigen Fällen nur die Transact-SQL-Anweisung, die den Fehler ausgelöst hat, zurückgesetzt und die Transaktion wird weiter verarbeitet.

In der Praxis bedeutet dies, dass einige der Anweisungen möglicherweise fehlschlagen und die Transaktion "teilweise abgeschlossen" bleibt. Für einen Anrufer gibt es möglicherweise keine Anzeichen für diesen Fehler.

Ein einfaches Beispiel:

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

Dieser Code würde 'erfolgreich' mit XACT_ABORT OFF ausgeführt und mit einem Fehler mit XACT_ABORT ON beendet ('INSERT INTO t2' wird nicht ausgeführt und eine Clientanwendung löst eine Ausnahme aus).

Als flexibleren Ansatz können Sie nach jeder Anweisung (alte Schule) @@ ERROR überprüfen oder TRY ... CATCH-Blöcke (MSSQL2005 +) verwenden. Persönlich ziehe ich es vor, XACT_ABORT auf ON zu setzen, wenn es keinen Grund für eine erweiterte Fehlerbehandlung gibt.

VladV
quelle
8

In Bezug auf Client-Timeouts und die Verwendung von XACT_ABORT, um sie zu verarbeiten, gibt es meiner Meinung nach mindestens einen sehr guten Grund, Timeouts in Client-APIs wie SqlClient zu verwenden, nämlich den Client-Anwendungscode vor Deadlocks zu schützen, die im SQL Server-Code auftreten. In diesem Fall ist der Client-Code fehlerfrei, muss sich jedoch selbst davor schützen, für immer zu blockieren, bis der Befehl auf dem Server ausgeführt wird. Wenn umgekehrt Client-Timeouts zum Schutz des Client-Codes vorhanden sein müssen, muss XACT_ABORT ON den Server-Code vor Client-Abbrüchen schützen, falls die Ausführung des Server-Codes länger dauert, als der Client warten möchte.

ionutm
quelle
1

Es wird in der Transaktionsverwaltung verwendet, um sicherzustellen, dass Fehler dazu führen, dass die Transaktion zurückgesetzt wird.

Dan Diplo
quelle