- Einleitung
- Transaktionen
- Geschachtelte Transaktionen
- Save TRAN und Save Points
- Error Handling
==Einleitung==
Die folgenden Beispiele beziehen sich auf die Pubs Datenbank, welche bei jeder neuen Installation eines SQL Servers bereits vorhanden sind. Sollten Sie eine frische Installation der "Pubs" Datenbank benötigen, folgen Sie dem Text.
- Führen Sie den folgenden osql Befehl aus um die Pubs Datenbank zu finden, wir benutzen dazu die Stored Procedure sp_detach_db.
osql -U sa -P "" -Q "exec sp_detach_db 'Pubs'"
- Löschen Sie die Datenbankdateien der "Pubs" Datenbank (pubs.mdf, pubs_log.ldf). Diese Dateien befinden sich im \Data Ordner.
- Die Neuinstallation der "Pubs" Datenbank benötigt das Instpubs.sql Skript.
osql -U sa -P "" -i
"C:\Program Files\Microsoft SQL Server\MSSQL\Install\InstPubs.sql"
Nach oben
==Transaktionen==
Transactions gruppieren eine Reihe von Aufgaben in eine einzelne. Jede Transaction beginnt mit einer bestimmten Aufgabe und endet erst dann wenn alle Aufgaben erfolgreich ausgeführt wurden. Wenn eine einzelne Aufgabe nicht ausgeführt werden kann, kann die Transaction nicht ausgeführt werden. Aus diesem Grund hat eine Transaction nur zwei Ergebnisse: Erfolg oder Fehler. Fehlerhafte Schritte ergeben eine fehlerhafte Transaction.
Benutzer können zwei oder mehrere Transact-SQL in eine einzelne Transaction mit folgenden Anweisungen gruppieren:
- Begin Transaction
- Rollback Transaction
- Commit Transaction
Läuft etwas mit den gruppierten Anweisungen schief, müssen alle Änderungen abgebrochen werden. Der Prozess um Änderungen umzukehren wird ROLLBACK genannt.
Wenn alles sauber funktioniert werden alle Änderungen zusammen in die Datenbank aufgenommen. In der SQL Terminologie nennt man dies COMMIT.
Hier ist ein kleines Beispiel für eine Transaction:
USE pubs
DECLARE @intErrorCode INT
BEGIN TRAN
UPDATE Authors
SET Phone = '415 354-9866'
WHERE au_id = '724-80-9391'
SELECT @intErrorCode =
ERROR
IF (@intErrorCode <> 0) GOTO PROBLEM
UPDATE Publishers
SET city = 'Calcutta', country = 'India'
WHERE pub_id = '9999'
SELECT @intErrorCode =
ERROR
IF (@intErrorCode <> 0) GOTO PROBLEM
COMMIT TRAN
PROBLEM:
IF (@intErrorCode <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
END
Bevor die Echtzeitverarbeitung startet sagt der Befehl
BEGIN TRAN das alle folgenden Anweisungen als eine Transaction zu behandeln sind, gefolgt von zwei
UPDATE Anweisungen. Wenn während der Ausführung keine Fehler auftreten werden diese Änderungen durch den Befehl
COMMIT TRAN bestätigt und in die Datenbank geschrieben. Sollten jedoch Fehler auftreten wird die Ausführung bei
PROBLEM weitergeführt. Nachdem der Server dem Benutzer eine Meldung ausgegeben hat, werden alle Änderungen rückgängig gemacht.
Nach oben
Geschachtelte Transaktionen
Der SQL Server erlaubt es Ihnen mehrere Transaktionen zu schachteln. Das bedeutet eine neue Transaktion kann gestartet werden wenn die vorherige noch nicht abgeschlossen ist. Transact-SQL ermöglicht es Ihnen mehrere Transaktion zu schachteln, hierzu wird der Befehl
BEGIN TRAN verwendet. Die automatische Variable
TRANCOUNT kann ausgeführt werden um das Level der Schachtelung aufzuheben
0 keine Verschachtelung,
1 indiziert eine Verschachtelung ein Level tiefer, usw..
Wird ein
COMMIT Befehl gegen eine Transaktion außer die äußerste ausgeführt, werden keine Änderungen in die Datenbank geschrieben - es vermindert lediglich die automatische Variable
TRANCOUNT. Ein
ROLLBACK wiederum funktioniert unabhängig von dem Level in welchem es ausgeführt wird, es macht alles rückgängig unabhängig vom Verschachtelungslevel. Wenn ein verschachtelter
COMMIT Befehl permanente Änderungen in die Datenbank geschrieben hat, kann ein äußerer
ROLLBACK Befehl dies nicht mehr rückgängig machen.
Wenn Sie explizit eine Transaktion starten erhöht sich der Zähler der automatischen Variable
TRANCOUNT von
0 zu
1 wenn Sie mit einem
COMMIT Befehl bestätigen, der Zähler verringert sich um
1 wenn Sie einen
ROLLBACK Befehl ausführen. Wie Sie sehen ist das Verhalten von
COMMIT und
ROLLBACK nicht symmetrisch, wenn Sie Transaktionen verschachteln vermindert
COMMIT das Verschachtelungslevel immer um
1 wie Sie in Abbildung 1 sehen können. Der
ROLLBACK Befehl auf der anderen Seite widerruft die komplette Transaction (Abbildung 2). Die Ungleichmäßigkeit zwischen
COMMIT und
ROLLBACK ist der Schlüssel um Fehler in verschachtelten Transaktionen zu handhaben.
Abbildung 1: Ein
COMMIT gleicht immer ein
BEGIN TRANSACTION durch vermindern des Versachtelungszähler um
1 aus.
Abbildung 2: Ein einzelnes
ROLLBACK löst die gesamte Transaktion auf.
Wie Sie in Abbildung 1 und 2 sehen können, können Sie Transaktionen verschachteln und die automatische Variable
TRANCOUNT benutzen um das Level zu bestimmen. Sie haben außerdem gelernt, dass sich
COMMIT und
ROLLBACK nicht symmetrisch verhalten:
COMMIT vermindert nur das Level der
TRANCOUNT Variable um 1.
ROLLBACK setzt das Level der
TRANCOUNT Variable auf 0.
Dies hat die Auswirkung das eine Transaktion nie komplett ausgeführt wird bis das letzte
COMMIT übergeben wird. Egal wie tief Ihre Verschachtelung ist, sie hat keine Auswirkung wenn das letzte
COMMIT nicht übergeben wird.
Hier ist ein Beispiel für eine verschachtelte Transaktion:
USE pubs
SELECT 'Before BEGIN TRAN', TRANCOUNT -- The value of
TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', TRANCOUNT -- The value of
TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', TRANCOUNT
-- The value of
TRANCOUNT is 2
DELETE titleauthor
COMMIT TRAN nested
Does nothing except decrement the value of TRANCOUNT
SELECT 'After COMMIT TRAN nested',
TRANCOUNT
The value of TRANCOUNT is 1
ROLLBACK TRAN
SELECT 'After ROLLBACK TRAN',
TRANCOUNT The value of TRANCOUNT is 0
-- because ROLLBACK TRAN always rolls back all transactions and sets
--
TRANCOUNT to 0.
SELECT TOP 5 au_id FROM titleauthor
In diesem Beispiel sehen wir, dass trotz des verschachtelten
COMMIT TRAN der äußere
ROLLBACK die Auswirkung der
DELETE titleauthor rückgängig macht.
Hier ist ein weiteres Beispiel einer verschachtelten Transaktion:
USE pubs
SELECT 'Before BEGIN TRAN', TRANCOUNT -- The value of
TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', TRANCOUNT -- The value of
TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', TRANCOUNT
-- The value of
TRANCOUNT is 2
DELETE titleauthor
ROLLBACK TRAN
SELECT 'After COMMIT TRAN nested', TRANCOUNT
-- The value of
TRANCOUNT is 0 because
ROLLBACK TRAN always rolls back all transactions and sets TRANCOUNT
-- to 0.
IF (
TRANCOUNT > 0) BEGIN
COMMIT TRAN Never makes it here cause of the ROLLBACK
SELECT 'After COMMIT TRAN', TRANCOUNT
END
SELECT TOP 5 au_id FROM titleauthor
</code>
{br}
In diesem Beispiel erreicht die Ausführung niemals den '''COMMIT TRAN''' auf Grund der '''ROLLBACK TRAN''', sie macht alle Transaktionen rückgängig die zur Zeit ausgeführt werden und setzt den '''TRANCOUNT''' wieder auf '''0'''. Sofern '''ROLLBACK TRAN''' ohne Sicherungspunkt ausgeführt wird, wird '''ROLLBACK TRAN''' alle Transaktionen rückgängig machen und den '''TRANCOUNT''' wieder auf '''0''' setzen. Egal in welchem Zusammenhang sie aufgerufen wird.{br}
{br}
{TOP}
{br}
{br}
[anchor|#4]
==Save TRAN und Save Points==
Savepoints bieten einen Vorgang um Teile einer Transaktion rückgängig zu machen. Der Benutzer kann einen Savepoint oder eine Markierung in einer Transaktion setzen. Der Savepoint definiert einen Bereich zu der die Transaktion zurückkehren kann, wenn ein Abschnitt der Transaktion bedingungsweise abgebrochen wird. Der SQL Server bietet Ihnen die Möglichkeit einen Savepoint mit Hilfe der '''SAVE TRAN''' zu setzen, welche den Wert des '''TRANCOUNT''' nicht beeinflusst. Ein Rückschritt zu einem Savepoint (nicht einer Transaktion) beeinflusst den Wert der '''TRANCOUNT''' ebenfalls nicht. Allerdings muss das '''ROLLBACK''' explizit den Namen des Savepoints beinhalten, sonst wird die komplett Transaktion rückgängig gemacht.{br}
{br}
Das folgende Skript zeigt wie man Savepoints benutzt:{br}
{br}
<code sql>USE pubs
SELECT 'Before BEGIN TRAN main',
TRANCOUNT
The value of TRANCOUNT is 0
BEGIN TRAN main
SELECT 'After BEGIN TRAN main',
TRANCOUNT
The value of TRANCOUNT is 1
DELETE sales
SAVE TRAN sales -- Mark a save point
SELECT 'After SAVE TRAN sales',
TRANCOUNT
The value of TRANCOUNT is still 1
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested',
TRANCOUNT
The value of TRANCOUNT is 2
DELETE titleauthor
SAVE TRAN titleauthor -- Mark a save point
SELECT 'After SAVE TRAN titleauthor',
TRANCOUNT
The value of TRANCOUNT is still 2
ROLLBACK TRAN sales
SELECT 'After ROLLBACK TRAN sales',
TRANCOUNT
The value of TRANCOUNT is still 2
SELECT TOP 5 au_id FROM titleauthor
IF (
TRANCOUNT > 0) BEGIN
ROLLBACK TRAN
SELECT 'AFTER ROLLBACK TRAN', TRANCOUNT
-- The value of
TRANCOUNT is 0 because
ROLLBACK TRAN always rolls back all transactions and sets TRANCOUNT
-- to 0.
END
SELECT TOP 5 au_id FROM titleauthor</code>{br}
{TOP}
{br}
{br}
[anchor|#5]
==Error Handling==
Die hier gezeigten Beispiele sind spezifisch für Stored Procedures, da sie die gewünschte Methode sind um mit einer Datenbank zu interagieren. Wird ein Fehler in einer Stored Procedure gefunden, ist das Beste was Sie machen können die sequentielle Ausführung des Codes zu stoppen und{br}
{br}
* entweder in ein anderes Code Segment der Prozedur zu springen (abzweigen)
* oder die Kontrolle wieder an die aufrufende Applikation zurückgeben.
{br}
Die automatische Variable '''ERROR''' wird benutzt um das Error Handling auszuführen. Sie beinhaltet die Fehler ID die von der letzten ausgeführten SQL Anweisung des Benutzers. Wenn eine Anweisung erfolgreich ausgeführt wird ist der Wert der '''ERROR''' Variable '''0'''. Um festzulegen ob eine Anweisung erfolgreich ausgeführt wurde wird eine '''IF''' Anweisung direkt nach der Ausführung des Statements ausgeführt um den Wert der '''ERROR''' Variable zu prüfen. Es ist unerlässlich die '''ERROR''' Variable nach der Ausführung eines Statements zu prüfen, weil der Wert nach der erfolgreichen Ausführung des nächsten Statements wieder auf '''0''' gesetzt wird. Tritt ein abfangbarer Fehler auf hat '''ERROR''' einen Wert größer '''0'''. Der SQL Server setzt den Wert nach jedem erfolgreichen Befehl wieder auf '''0''', d.h. sie müssen den Fehlerwert sofort erfassen. Meistens testen Sie die '''ERROR''' Variable auf Änderungen nach jeder '''INSERT''', '''UPDATE''' oder '''DELETE''' Anweisung.{br}
{br}
<code sql>CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),
@title VARCHAR(20), @title_type CHAR(12))
AS
BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)
IF (
ERROR <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END
INSERT titleauthor(au_id, title_id)
VALUES (@au_id, @title_id)
IF (ERROR <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END
COMMIT TRAN
RETURN 0</code>
{br}
Diese Art der Lösung birgt beträchtige Wiederholung, gerade dann wenn in Ihrer Unternehmenslogik die Implementierung von mehr als zwei Transact-SQL benötigt wird. Eine elegantere Lösung ist es den Code in eine typische Bearbeitungsprozedur zu gruppieren:{br}
{br}
<code sql>CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),
@title VARCHAR(20), @title_type CHAR(12))
AS
BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)
IF (
ERROR <> 0) GOTO ERR_HANDLER
INSERT titleauthor(au_id, title_id)
VALUES (@au_id, @title_id)
IF (@@ERROR <> 0) GOTO ERR_HANDLER
COMMIT TRAN
RETURN 0
ERR_HANDLER:
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
Nach oben