Auf meiner unendlichen Suche, mich mit einer sicheren Transaktion in den Fuß zu schießen, habe ich anscheinend noch mehr Möglichkeiten gefunden, um den Questzweck zu erfüllen. Die Sicherungs-Transaktionsklausel selbst kommt diesmal nicht in Frage, aber deshalb habe ich den folgenden Code geschrieben.
Betrachten Sie das folgende vollständige Beispiel mit verschachtelten Fehlerbehandlungsroutinen:
begin try
begin try
select 'Step 1';
end try
begin catch
select 'Step 1 handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch;
begin try
select 'Step 2';
raiserror('Step 2 error', 16, 1);
end try
begin catch
select 'Step 2 handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch;
end try
begin catch
select 'Outer handler - handling ''' + error_message() + '''';
goto commit_and_exit;
end catch
commit_and_exit:
raiserror('Error raised for the caller to see', 16, 1);
Es ist dokumentiert, dass
GOTO
Anweisungen können verwendet werden, um zu einer Beschriftung innerhalb desselbenTRY
oderCATCH
Blocks zu springen oder einenTRY
oderCATCH
Block zu verlassen .
Oder kann es?
In Anbetracht des obigen Codes würde ein vernünftiger Programmierer die Ausgabe berechnen
Schritt 1
Schritt 2
Schritt 2 Handler - Behandlung von 'Schritt 2 Fehler'
<Fehler, den der Anrufer sehen muss>
In der Tat ist was passiert:
Schritt 1
Schritt 2
Schritt 2 Handler - Behandlung von 'Schritt 2 Fehler'
Äußerer Handler - Behandlung 'Fehler, den der Anrufer sehen kann'
<Fehler, den der Anrufer sehen muss>
Beim schrittweisen Debuggen kann ich sehen, dass das Steuerelement die try / catch-Blöcke vollständig verlässt, dann ein Fehler ausgelöst wird, das Steuerelement an den äußersten catch
Block zurückgegeben wird, dieser Block ausgeführt wird, das Steuerelement commit_and_exit:
erneut ausgeführt wird und dieser letzte Block ausgeführt wird wieder .
Wenn Sie einige commit tran
s oder rollback trans
s unter haben commit_and_exit:
, werden Sie versuchen, die Übertragung zweimal zu begehen. Mit vorstellbaren Ergebnissen, da der Anrufer äußere Transaktionen starten kann.
Ich habe auch versucht, ein anderes Etikett end_of_outer:
direkt vor dem äußeren zu erstellen end try
, damit das Steuerelement den äußeren try
Block "normal" verlässt . Interessanterweise machte das keinen Unterschied.
Was zum Teufel ist los und wie geht das richtig?
XACT_STATE() = 1
, sodass wir zu einem Speicherpunkt zurückkehren und weitermachen). Ich bin jedoch mehr besorgt über das Prinzip der Fehlerbehandlung, selbst wenn Transaktionen vorhanden sind. Jeder Code danach commit_and_exit:
wird zweimal ausgeführt.