📖 Grundlagen: Was ist eine Transaktion?
-- Explizite Transaktion (klare Grenzen)
BEGIN TRANSACTION;
UPDATE Konto SET Saldo = Saldo - 100 WHERE KontoNr = 123;
UPDATE Konto SET Saldo = Saldo + 100 WHERE KontoNr = 456;
COMMIT;
-- Implizite Transaktion: Jede einzelne Anweisung ist für sich eine Transaktion
UPDATE Konto SET Saldo = Saldo - 100 WHERE KontoNr = 123; -- automatischer Commit
✅ Explizite Transaktionen – vollständige Kontrolle
BEGIN TRAN;
INSERT INTO Bestellungen (Kunde, Betrag) VALUES (101, 250.00);
DECLARE @orderId INT = SCOPE_IDENTITY();
INSERT INTO BestellPositionen (BestellID, Produkt, Menge) VALUES (@orderId, 'Laptop', 1);
IF (@@ERROR != 0) -- Fehlerprüfung (vereinfacht, besser mit TRY/CATCH)
ROLLBACK;
ELSE
COMMIT;
⚙️ Implizite Transaktionen – jedes Statement als eigene Einheit
-- Standard Verhalten (Autocommit, implizit ohne IMPLICIT_TRANSACTIONS)
UPDATE Produkte SET Preis = Preis * 1.05 WHERE Kategorie = 'Elektronik'; -- sofort committet
-- Einschalten des "impliziten Transaktionsmodus" (ähnlich anderer DBMS)
SET IMPLICIT_TRANSACTIONS ON;
UPDATE Produkte SET Preis = Preis * 1.05 WHERE Kategorie = 'Elektronik'; -- Transaktion startet automatisch
IF (@@ROWCOUNT > 0)
COMMIT;
ELSE
ROLLBACK;
SET IMPLICIT_TRANSACTIONS OFF;
📊 Vergleich: Explizite vs. implizite Transaktionen
| Merkmal | Explizite Transaktion (BEGIN TRAN) | Implizite Transaktion (Autocommit) |
|---|---|---|
| Steuerung | Entwickler steuert Start und Ende | SQL Server öffnet/committet automatisch pro Statement |
| Mehrere Änderungen | Mehrere Statements in einer logischen Einheit | Jedes Statement ist isoliert (kein gemeinsamer Commit) |
| Fehlerbehandlung | ROLLBACK möglich, um vorherige Änderungen rückgängig zu machen | Fehler in einem Statement lässt vorheriges Statement bereits committet (keine atomare Gruppe) |
| Sperrverhalten | Sperren können über die gesamte Transaktion gehalten werden | Sperren werden nach jeder Anweisung freigegeben (kurze Dauer) |
| Typische Verwendung | Banktransfers, Bestellprozesse, mehrstufige Änderungen | Standard für einfache DML, Reports, einmalige Updates |
⚠️ Typische Probleme durch fehlende explizite Transaktionen
-- Gefährlich: Keine atomare Sicherung
UPDATE Konto SET Saldo = Saldo - 100 WHERE KontoNr = 123;
-- Angenommen, hier tritt ein Fehler auf (Server neustart, Timeout, etc.)
UPDATE Konto SET Saldo = Saldo + 100 WHERE KontoNr = 456;
→ Ergebnis: 100 Euro sind verloren (weil erste Änderung committet, zweite nicht ausgeführt).
-- Korrekt mit expliziter Transaktion
BEGIN TRANSACTION;
UPDATE Konto SET Saldo = Saldo - 100 WHERE KontoNr = 123;
UPDATE Konto SET Saldo = Saldo + 100 WHERE KontoNr = 456;
COMMIT;
Entwickler, die aus anderen Datenbanken (z. B. Oracle mit dessen Standardverhalten) kommen, sind oft überrascht, dass SQL Server standardmäßig autocommittet. Daher: Bilden Sie logische Einheiten immer mit BEGIN TRAN.
✅ Best Practices für explizite Transaktionen
- So kurz wie möglich: Nur die unbedingt notwendigen DML-Operationen in die Transaktion packen. Keine Benutzerdialoge oder längere Berechnungen innerhalb der Transaktion.
- TRY/CATCH verwenden: Im Fehlerfall sofort ROLLBACK ausführen, um offene Sperren zu vermeiden.
- Geeignete Isolationsstufe wählen: READ COMMITTED ist meist ausreichend. Für leseintensive Szenarien kann READ UNCOMMITTED oder SNAPSHOT besser sein.
- Immer COMMIT oder ROLLBACK: Jede Transaktion muss beendet werden. Nutzen Sie @@TRANCOUNT vor Batch‑Ende, um sicherzustellen, dass keine Transaktion offen bleibt.
- Verwenden Sie SET XACT_ABORT ON: Bei Laufzeitfehlern wird die Transaktion automatisch zurückgesetzt – vereinfacht die Fehlerbehandlung enorm.
-- Beispiel einer robusten expliziten Transaktion mit XACT_ABORT
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO Log (Ereignis) VALUES ('Start Update');
UPDATE GrossTabelle SET Status = 'Aktiv' WHERE Kategorie = 'X';
DELETE FROM AlteDaten WHERE Erstelldatum < '2022-01-01';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
THROW;
END CATCH
🔄 Wann sind implizite Transaktionen (Autocommit) ausreichend?
- Einzelne INSERT/UPDATE/DELETE, die keine Abhängigkeit zu anderen Anweisungen haben.
- Reine Leseabfragen (SELECT) – hier gibt es keine dauerhaften Änderungen (außer man nutzt SELECT INTO).
- DDL-Anweisungen wie CREATE/ALTER/DROP – diese sind meist atomar.
- Reporting- oder Diagnose-Queries, bei denen Konsistenz über mehrere Schritte nicht benötigt wird.
🔁 Verschachtelte Transaktionen (@@TRANCOUNT)
PRINT @@TRANCOUNT; -- 0
BEGIN TRAN; -- T1
INSERT INTO Tabelle VALUES (1);
BEGIN TRAN; -- T2 (verschachtelt)
INSERT INTO Tabelle VALUES (2);
COMMIT; -- reduziert @@TRANCOUNT auf 1, keine dauerhafte Änderung
COMMIT; -- schreibt beide Inserts endgültig
📌 Zusammenfassung: Explizit vs. Implizit
- Implizite Transaktionen (Autocommit): Standard, jede Einzelanweisung ist eine eigene Transaktion. Einfach, schnell, aber nicht für logische Einheiten geeignet.
- Explizite Transaktionen (BEGIN TRAN … COMMIT/ROLLBACK): Geben vollständige Kontrolle über atomare Gruppen. Unverzichtbar für Datenkonsistenz bei mehreren Änderungen.
- Modus SET IMPLICIT_TRANSACTIONS ON: Nicht empfohlen – leicht misszuverstehen und oft Quelle offener Transaktionen.
- Beste Praxis: Immer TRY/CATCH + XACT_ABORT ON verwenden, Transaktionen kurz halten und @@TRANCOUNT im Auge behalten.