Rollbacks und Commits in gespeicherten Prozeduren und Triggern

Die Ausführung einer Transact-SQL-Anweisung vom Typ ROLLBACK TRANSACTION oder COMMIT TRANSACTION innerhalb einer gespeicherten Prozedur oder innerhalb eines Triggers ist zwar möglich, kann jedoch Fehler verursachen.

In gespeicherten Prozeduren

Wenn @@TRANCOUNT einen anderen Wert beim Beenden als beim Ausführungsbeginn einer gespeicherten Prozedur aufweist, tritt ein informatorischer Fehler (266) auf. Dies kann in zwei Varianten geschehen:

  • Eine gespeicherte Prozedur wird mit einem @@TRANCOUNT von 1 oder größer aufgerufen, und die gespeicherte Prozedur führt eine ROLLBACK TRANSACTION-Anweisung aus. @@TRANCOUNT wird auf 0 reduziert und verursacht einen Fehler 266, wenn die gespeicherte Prozedur abgeschlossen wird.
  • Eine gespeicherte Prozedur wird mit einem @@TRANCOUNT von 1 oder größer aufgerufen, und die gespeicherte Prozedur führt eine COMMIT TRANSACTION-Anweisung aus. @@TRANCOUNT wird um 1 reduziert und verursacht einen Fehler 266, wenn die gespeicherte Prozedur abgeschlossen wird. Wenn allerdings BEGIN TRANSACTION nach COMMIT TRANSACTION ausgeführt wird, tritt der Fehler nicht auf.

In Triggern

Ein Trigger arbeitet so, als ob eine ausstehende Transaktion aktiv wäre, wenn der Trigger ausgeführt wird. Dies trifft zu, wenn es sich bei der Anweisung, die den Trigger ausgelöst hat, um eine implizite oder explizite Transaktion handelt.

Wenn eine Anweisung im Autocommitmodus mit der Ausführung beginnt, liegt implizit eine BEGIN TRANSACTION-Anweisung vor, die das Wiederherstellen aller Änderungen ermöglicht, die von der Anweisung generiert wurden, falls ein Fehler festgestellt wird. Diese implizite Transaktion hat keinerlei Auswirkungen auf andere Anweisungen im Batch, da für sie beim Beenden der Anweisung entweder ein Commit oder ein Rollback ausgeführt wird. Die implizite Transaktion ist jedoch noch aktiv, wenn ein Trigger aufgerufen wird.

Bei der Ausführung eines Triggers wird eine implizite Transaktion gestartet. Wenn die Ausführung eines Triggers mit @@TRANCOUNT = 0 abgeschlossen wird, tritt ein Fehler 3609 auf, und der Batch wird beendet. Aus diesem Grund wird empfohlen, innerhalb von Triggern keine ROLLBACK TRANSACTION-Anweisungen, die @@TRANCOUNT auf 0 zurücksetzen, und COMMIT TRANSACTION-Anweisungen, die @@TRANCOUNT auf 0 reduzieren können, zu verwenden. Die Ausgabe einer BEGIN TRANSACTION-Anweisung nach einem Rollback verhindert zwar das Auflösen des Fehlers, es kann stattdessen aber zu Problemen mit der Anwendungslogik kommen.

Es ist wichtig zu wissen, dass eine im Trigger ausgegebene BEGIN TRANSACTION-Anweisung tatsächlich zum Start einer geschachtelten Transaktion führt. In dieser Situation gilt die Ausführung einer COMMIT TRANSACTION-Anweisung nur für die verschachtelte Transaktion. Da eine geschachtelte BEGIN TRANSACTION-Anweisung beim Ausführen eines Rollbacks für geschachtelte Transaktionen ignoriert wird, wird bei einer im Trigger ausgeführten ROLLBACK TRANSACTION-Anweisung immer über alle BEGIN TRANSACTION-Anweisungen hinaus, die vom Trigger selbst ausgegeben wurden, ein Rollback ausgeführt. ROLLBACK führt ein Rollback bis zur äußersten Transaktion aus und setzt @@TRANCOUNT auf 0.

Bei Verwendung von ROLLBACK TRANSACTION in einem Trigger müssen Sie das folgende Verhalten beachten:

  • Für alle Datenänderungen, die bis zu diesem Zeitpunkt in der aktuellen Transaktion vorgenommen worden sind, wird ein Rollback ausgeführt, einschließlich aller Änderungen, die vom Trigger vorgenommen wurden.
  • Der Trigger setzt die Ausführung aller verbleibenden Anweisungen nach der ROLLBACK-Anweisung fort. Wenn durch eine dieser Anweisungen Daten geändert werden, wird für die Änderungen kein Rollback ausgeführt.
  • Ein ROLLBACK in einem Trigger schließt alle Cursor und hebt deren Zuordnung auf, die in dem Batch mit der Anweisung, die den Trigger auslöste, deklariert und geöffnet wurden. Dazu gehören auch die in gespeicherten Prozeduren deklarierten und geöffneten Cursor, die von dem Batch aufgerufen wurden, der den Trigger ausgelöst hat. Cursor, die in einem Batch vor demjenigen Batch, der den Trigger ausgelöst hat, deklariert wurden, werden einfach geschlossen. Davon ausgenommen sind STATIC- oder INSENSITIVE-Cursor, die offen bleiben, wenn Folgendes gilt:
    • CURSOR_CLOSE_ON_COMMIT ist auf OFF festgelegt.
    • Der statische Cursor ist ein synchroner oder ein vollständig aufgefüllter asynchroner Cursor.

Anstelle der Verwendung von ROLLBACK TRANSACTION kann die SAVE TRANSACTION-Anweisung zum Ausführen eines teilweisen Rollbacks in einem Trigger verwendet werden.

Siehe auch

Konzepte

Schachteln von Transaktionen

Andere Ressourcen

@@TRANCOUNT (Transact-SQL)
ROLLBACK TRANSACTION (Transact-SQL)
ROLLBACK WORK (Transact-SQL)
SAVE TRANSACTION (Transact-SQL)

Hilfe und Informationen

Informationsquellen für SQL Server 2005