Ich habe eine gespeicherte Prozedur, die nur 3 gespeicherte Prozeduren in ihnen ausführt. Ich verwende nur 1 Parameter zum Speichern, wenn der Master-SP erfolgreich ist.
Wenn die erste gespeicherte Prozedur in der gespeicherten Hauptprozedur einwandfrei funktioniert, die zweite gespeicherte Prozedur jedoch fehlschlägt, werden dann automatisch alle SPs in der Hauptprozedur zurückgesetzt, oder muss ich einen Befehl ausführen?
Hier ist meine Vorgehensweise:
CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName, errorMessage, systemDate)
values ('spSavesomename', ERROR_MESSAGE(), getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
sql-server
stored-procedures
transaction
user2483342
quelle
quelle
spNewBilling3
ein Fehler ausgelöst wird, Sie aber nicht zurücksetzenspNewBilling2
oder möchtenspNewBilling1
, dann entfernen Sie einfach[begin|rollback|commit] transaction createSavebillinginvoice
ausspSavesomename
.Antworten:
Wenn nur der in der Frage angegebene Code verwendet wird und angenommen wird, dass keiner der drei Unterprozesse eine explizite Transaktionsbehandlung aufweist, wird ein Fehler in einem der drei Unterprozesse abgefangen, und der
ROLLBACK
imCATCH
Block enthaltene Code wird alle zurücksetzen der Arbeit.ABER hier sind einige Dinge zu beachten (zumindest in SQL Server):
Es gibt immer nur eine echte Transaktion (die erste), egal wie oft Sie anrufen
BEGIN TRAN
BEGIN TRAN
wird der Transaktionszähler um 1 erhöht, unabhängig davon, ob er benannt wurde oder nicht.SELECT @@TRANCOUNT;
COMMIT
Befehle, die@@TRANCOUNT
bei 2 oder höher ausgegeben werden, reduzieren den Transaktionszähler nacheinander.COMMIT
ausgestellt wird, wenn das um@@TRANCOUNT
ist1
Durch das Speichern von Punkten können Sie eine Teilmenge der Arbeit innerhalb der Transaktion erstellen, die rückgängig gemacht werden kann.
SAVE TRAN {save_point_name}
Befehl angelegt / markiertROLLBACK {save_point_name}
. (mehr dazu weiter unten)SAVE TRAN {save_point_name}
, einschließlich aller Speicherpunkte, die erstellt wurden, nachdem der zurückgesetzte erstellt wurde (daher die "Verschachtelung").SAVE TRAN
können nur rückgängig gemacht werden, indemROLLBACK
die gesamte Transaktion vollständig ausgeführt wird.COMMIT
Zeitpunkts@@TRANCOUNT
von 2 oder höher hat keine Auswirkung auf das Speichern von Punkten (da es auch außerhalb dieses Zählers keine Transaktionsstufen über 1 gibt).Sie können keine bestimmten benannten Transaktionen festschreiben. Der "Transaktionsname"
COMMIT
wird ignoriert und dient nur der Lesbarkeit.Bei einer
ROLLBACK
Ausgabe ohne Namen werden immer ALLE Transaktionen zurückgesetzt.Ein
ROLLBACK
ausgestelltes mit einem Namen muss entweder entsprechen:Unter der Annahme, dass keine
SAVE TRAN
mit demselben Transaktionsnamen aufgerufen wurde, werden ALLE Transaktionen zurückgesetzt.Dieses Verhalten macht alle Änderungen "rückgängig", die seit dem letzten
SAVE TRAN {save_point_name}
Aufruf vorgenommen wurden.SAVE TRAN
Befehle mit ihrem Namen ausgegeben wurden, macht jeder ROLLBACK dieses Transaktionsnamens jeden Speicherpunkt rückgängig, bis keiner mehr von diesem Namen übrig ist. Danach wird durch ein ROLLBACK mit diesem Namen ALLE Transaktionen zurückgesetzt.Angenommen, die folgenden Befehle wurden in der angegebenen Reihenfolge ausgeführt:
Nun, wenn Sie Probleme haben (jedes der folgenden Szenarien ist unabhängig voneinander):
ROLLBACK TRAN B
einmal: "DML Query 4" wird rückgängig gemacht.@@TRANCOUNT
ist noch 2.ROLLBACK TRAN B
zweimal: "DML-Abfrage 4" wird rückgängig gemacht, und dann tritt ein Fehler auf, da für "B" kein entsprechender Speicherpunkt vorhanden ist.@@TRANCOUNT
ist noch 2.ROLLBACK TRAN A
einmal: "DML-Abfrage 4" und "DML-Abfrage 3" werden rückgängig gemacht.@@TRANCOUNT
ist noch 2.ROLLBACK TRAN A
zweimal: "DML-Abfrage 4", "DML-Abfrage 3" und "DML-Abfrage 2" werden rückgängig gemacht.@@TRANCOUNT
ist noch 2.ROLLBACK TRAN A
Dreimal: "DML Query 4", "DML Query 3" und "DML Query 2" werden rückgängig gemacht. Dann wird die gesamte Transaktion rückgängig gemacht (alles, was übrig blieb, war "DML-Abfrage 1").@@TRANCOUNT
ist jetzt 0.COMMIT
einmal:@@TRANCOUNT
geht runter auf 1.COMMIT
einmal und dannROLLBACK TRAN B
einmal:@@TRANCOUNT
geht zu 1. Dann wird "DML Query 4" rückgängig gemacht (was beweist, dass COMMIT nichts getan hat).@@TRANCOUNT
ist noch 1.Transaktionsnamen und Speicherpunktnamen:
Eine gespeicherte Prozedur ist an sich keine implizite Transaktion. Jede Abfrage, wenn keine explizite Transaktion gestartet wurde, ist eine implizite Transaktion. Aus diesem Grund sind explizite Transaktionen für einzelne Abfragen nicht erforderlich, es sei denn, es gibt einen programmgesteuerten Grund für die
ROLLBACK
Ausführung von a. Andernfalls führt ein Fehler in der Abfrage zu einem automatischen Rollback dieser Abfrage.Wenn eine gespeicherte Prozedur
@@TRANCOUNT
aufgerufen wird, muss sie mit dem Wert beendet werden , der dem Wert entspricht , mit dem sie aufgerufen wurde. Das heißt, Sie können nicht:BEGIN TRAN
in der Prozedur, ohne sie festzuschreiben, und erwarten Sie, dass sie in der aufrufenden / übergeordneten Prozedur festgeschrieben wird.ROLLBACK
wenn eine explizite Transaktion vor dem Aufruf des Procs gestartet wurde, da diese@@TRANCOUNT
auf 0 zurückgesetzt wird.Wenn Sie eine gespeicherte Prozedur mit einer Transaktionsanzahl beenden, die höher oder niedriger ist als beim Starren, wird eine Fehlermeldung angezeigt, die der folgenden ähnelt:
Tabellenvariablen sind wie reguläre Variablen nicht an Transaktionen gebunden.
In Bezug auf die Transaktionsbehandlung in Prozessen, die entweder unabhängig aufgerufen werden können (und daher eine Transaktionsbehandlung benötigen) oder von anderen Prozessen aufgerufen werden können (und daher keine Transaktionsbehandlung benötigen): Dies kann auf verschiedene Arten erfolgen.
Die Art und Weise , dass ich es seit einigen Jahren wurde der Handhabung gut zu funktionieren scheint , ist nur
BEGIN
/COMMIT
/ROLLBACK
auf der äußersten Schicht. Sub-Proc-Aufrufe überspringen einfach die Transaktionsbefehle. Ich habe unten beschrieben, was ich in jeden Proc stecke (nun, jeder, der eine Transaktionsabwicklung benötigt).DECLARE @InNestedTransaction BIT;
Anstelle von einfach
BEGIN TRAN
, mache:Anstelle von einfach
COMMIT
, mache:Anstelle von einfach
ROLLBACK
, mache:Diese Methode sollte unabhängig davon, ob die Transaktion in SQL Server oder auf App-Ebene gestartet wurde, gleich funktionieren.
Für die vollständige Vorlage dieser Transaktion im Umgang mit
TRY...CATCH
Konstrukts, bitte meine Antwort auf die folgende Frage DBA.SE sehen: Müssen wir Transaktion in C # -Code sowie in Stored Procedure zu handhaben .Abgesehen von den "Grundlagen" gibt es einige zusätzliche Nuancen von Transaktionen, die zu beachten sind:
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 VerwendungOPENQUERY
(oder bei Verbindungsservern im Allgemeinen), und auf dem fernen System tritt ein Fehler auf. Während die meisten Fehler mit abgefangen werden könnenTRY...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. MeistensTRY...CATCH
bewältigt es die meisten Situationen und überflüssig daher die Notwendigkeit fürXACT_ABORT ON
. Wenn Sie jedochOPENQUERY
(und möglicherweise ein anderes Szenario, an das ich mich momentan nicht erinnere) verwenden, müssen Sie es dennoch verwendenSET XACT_ABORT ON;
.Innerhalb eines Triggers
XACT_ABORT
wird implizit auf gesetztON
. Dies führt dazu, dass ein Fehler im Trigger die gesamte DML-Anweisung abbricht, die den Trigger ausgelöst hat.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 verwendenTRY...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 denCATCH
Block übertragen. Wenn dies der FallXACT_ABORT
istOFF
, wird die Transaktion dieCOMMIT
meiste Zeit noch aktiv sein, und Sie müssen oder höchstwahrscheinlichROLLBACK
. Wenn jedoch bestimmte Batch-Abbruch-Fehler auftreten (z. B. mitOPENQUERY
) oder wenn dies der FallXACT_ABORT
istON
, befindet sich die Transaktion in einem neuen Zustand, "unverbindlich". In diesem StatusCOMMIT
können Sie keine DML-Operationen ausführen. Alles, was Sie tun können, istROLLBACK
undSELECT
Aussagen. In diesem "nicht festlegbaren" Zustand wurde die Transaktion jedoch zurückgesetzt, nachdem ein Fehler aufgetreten ist, und die Ausstellung der TransaktionROLLBACK
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 mitXACT_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
undXACT_STATE() <> 0
gleichwertig prüfen . Auf der anderen Seite, wennXACT_ABORT
istOFF
und es eine aktive Transaktion, dann ist es möglich , einen Zustand entweder zu haben1
oder-1
in demCATCH
Block, die die Ausgabe für die Möglichkeit erlaubtCOMMIT
stattROLLBACK
(obwohl ich nicht von einem Fall denken kann , wenn jemand würde wollenCOMMIT
wenn die Transaktion verbindlich ist). Weitere Informationen und Recherchen zur VerwendungXACT_STATE()
innerhalb einesCATCH
Blocks mitXACT_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 gibtXACT_STATE()
, der dazu führt, dass er1
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 wirdAnmerkungen zum Originalcode:
BEGIN
undEND
um jedenEXEC
Anruf nichtquelle
Compile errors, such as syntax errors, that prevent a batch from running
undErrors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
. Aber sie kommen nicht sehr oft vor, und wenn Sie eine solche Situation finden, beheben Sie sie entweder (wenn es sich um einen Fehler im Code handelt) oder platzieren Sie sie in einem Unterprozess (EXEC
odersp_executesql
), damitTRY...CATCH
sie abgefangen werden können.Ja, wenn aufgrund eines Fehler-Rollback-Codes in der catch-Anweisung Ihrer gespeicherten Hauptprozedur ein Rollback aller Operationen ausgeführt wird, die von einer direkten Anweisung oder von einer Ihrer darin verschachtelten gespeicherten Prozeduren ausgeführt werden.
Auch wenn Sie in Ihren verschachtelten gespeicherten Prozeduren keine explizite Transaktion angewendet haben, verwendet diese gespeicherte Prozedur dennoch eine implizite Transaktion und schreibt sie nach Abschluss fest, ABER entweder Sie haben eine explizite oder eine implizite Transaktion in verschachtelten gespeicherten gespeicherten Prozeduren festgeschrieben Rollback aller Aktionen dieser verschachtelten gespeicherten Prozeduren, wenn die gespeicherte Hauptprozedur fehlschlägt und die Transaktion rückgängig gemacht wird.
Jedes Mal, wenn die Transaktion festgeschrieben oder zurückgesetzt wird, basierend auf der Aktion, die am Ende der äußersten Transaktion ausgeführt wurde. Wenn die äußere Transaktion festgeschrieben ist, werden auch die inneren geschachtelten Transaktionen festgeschrieben. Wenn die äußere Transaktion zurückgesetzt wird, werden auch alle inneren Transaktionen zurückgesetzt, unabhängig davon, ob die inneren Transaktionen einzeln festgeschrieben wurden oder nicht.
Als Referenz http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx
quelle