Standardmäßig werden Transaktionen die meiste Zeit nicht automatisch zurückgesetzt / abgebrochen, wenn ein Fehler auftritt. Dies ist normalerweise kein Problem, solange Sie über eine ordnungsgemäße Fehlerbehandlung verfügen und sich ROLLBACK
selbst anrufen . Manchmal werden die Dinge jedoch kompliziert, z. B. bei Batch-Abbruch-Fehlern oder bei der Verwendung OPENQUERY
(oder bei Verbindungsservern im Allgemeinen), und auf dem fernen System tritt ein Fehler auf. Während die meisten Fehler mit abgefangen werden können TRY...CATCH
, gibt es zwei, die nicht auf diese Weise abgefangen werden können (ich kann mich jedoch nicht an die erinnern, die gerade vorliegen - Nachforschungen anstellen). In diesen Fällen müssen Sie verwenden, SET XACT_ABORT ON
um die Transaktion ordnungsgemäß zurückzusetzen.
SET XACT_ABORT ON bewirkt, dass SQL Server eine Transaktion (falls eine aktiv ist) sofort zurücksetzt und den Stapel abbricht, wenn ein Fehler auftritt. Diese Einstellung war vor SQL Server 2005 vorhanden, mit dem das TRY...CATCH
Konstrukt eingeführt wurde. Meistens TRY...CATCH
bewältigt es die meisten Situationen und überflüssig daher die Notwendigkeit für XACT_ABORT ON
. Wenn Sie jedoch OPENQUERY
(und möglicherweise ein anderes Szenario, an das ich mich momentan nicht erinnere) verwenden, müssen Sie es dennoch verwenden SET XACT_ABORT ON;
.
Sie sollten immer über eine ordnungsgemäße Fehlerbehandlung verfügen, insbesondere bei der Verwendung von Transaktionen. Das TRY...CATCH
in SQL Server 2005 eingeführte Konstrukt bietet eine Möglichkeit, mit fast allen Situationen umzugehen. Es ist eine willkommene Verbesserung gegenüber dem Testen @@ERROR
nach jeder Anweisung, was bei Fehlern beim Batch-Abbruch nicht viel geholfen hat.
TRY...CATCH
führte jedoch einen neuen "Staat" ein. Wenn Sie das Konstrukt nicht verwenden TRY...CATCH
und eine Transaktion aktiv ist und ein Fehler auftritt, können mehrere Pfade verwendet werden:
XACT_ABORT OFF
und Fehler beim Abbrechen der Anweisung: Die Transaktion ist noch aktiv und die Verarbeitung wird mit der nächsten Anweisung fortgesetzt , sofern vorhanden.
XACT_ABORT OFF
und die meisten Stapelabbruchfehler: Die Transaktion ist noch aktiv und die Verarbeitung wird mit dem nächsten Stapel fortgesetzt , sofern vorhanden.
XACT_ABORT OFF
und bestimmte Stapelabbruchfehler: Die Transaktion wird zurückgesetzt und die Verarbeitung wird mit dem nächsten Stapel fortgesetzt , falls vorhanden.
XACT_ABORT ON
und ein Fehler: Die Transaktion wird zurückgesetzt und die Verarbeitung wird mit dem nächsten Stapel fortgesetzt , falls vorhanden.
Bei Verwendung von TRY...CATCH
Batch-Abbruch-Fehlern wird der Batch jedoch nicht abgebrochen, sondern die Steuerung an den CATCH
Block übertragen. Wenn dies der Fall XACT_ABORT
ist OFF
, wird die Transaktion die COMMIT
meiste Zeit noch aktiv sein, und Sie müssen oder höchstwahrscheinlich ROLLBACK
. Wenn jedoch bestimmte Batch-Abbruch-Fehler auftreten (z. B. mit OPENQUERY
) oder wenn dies der Fall XACT_ABORT
ist ON
, befindet sich die Transaktion in einem neuen Zustand, "unverbindlich". In diesem Status COMMIT
können Sie keine DML-Operationen ausführen. Alles, was Sie tun können, ist ROLLBACK
und SELECT
Aussagen. In diesem "nicht festlegbaren" Zustand wurde die Transaktion jedoch zurückgesetzt, nachdem ein Fehler aufgetreten ist, und die Ausstellung der Transaktion ROLLBACK
ist nur eine Formalität, die jedoch erledigt werden muss.
Mit der Funktion XACT_STATE kann ermittelt werden, ob eine Transaktion aktiv, nicht festschreibbar oder nicht vorhanden ist. Es wird empfohlen (zumindest von einigen), diese Funktion im CATCH
Block zu überprüfen , um festzustellen, ob das Ergebnis -1
(dh nicht festgeschrieben) ist, anstatt zu testen, ob @@TRANCOUNT > 0
. Aber mit XACT_ABORT ON
, das sollte der einzig mögliche Zustand sein, in dem man sein kann, also scheint es, als würde man auf @@TRANCOUNT > 0
und XACT_STATE() <> 0
gleichwertig prüfen . Auf der anderen Seite, wenn XACT_ABORT
ist OFF
und es eine aktive Transaktion, dann ist es möglich , einen Zustand entweder zu haben 1
oder -1
in dem CATCH
Block, die die Ausgabe für die Möglichkeit erlaubt COMMIT
statt ROLLBACK
(obwohl ich nicht von einem Fall denken kann , wenn jemand würde wollenCOMMIT
wenn die Transaktion verbindlich ist). Weitere Informationen und Recherchen zur Verwendung XACT_STATE()
innerhalb eines CATCH
Blocks mit XACT_ABORT ON
finden Sie in meiner Antwort auf die folgende DBA.SE-Frage: In welchen Fällen kann eine Transaktion innerhalb des CATCH-Blocks festgeschrieben werden, wenn XACT_ABORT auf ON gesetzt ist? . Bitte beachten Sie, dass es einen kleinen Fehler gibt XACT_STATE()
, der dazu führt, dass er 1
in bestimmten Szenarien fälschlicherweise zurückgegeben wird : XACT_STATE () gibt 1 zurück, wenn es in SELECT mit einigen Systemvariablen, aber ohne FROM-Klausel verwendet wird
spNewBilling3
ein Fehler ausgelöst wird, Sie aber nicht zurücksetzenspNewBilling2
oder möchtenspNewBilling1
, dann entfernen Sie einfach[begin|rollback|commit] transaction createSavebillinginvoice
ausspSavesomename
.