Nein SAVE TRANSACTION
. Ich habe nie einen Grund dafür gefunden. Ich weiß, dass einige Leute es vorziehen, aber bei allem, was ich jemals an einem Ort getan habe, an dem ich gearbeitet habe, implizierte die Vorstellung eines Fehlers, der in einer der verschachtelten Ebenen auftrat, dass die bereits geleistete Arbeit ungültig war. Durch die Verwendung SAVE TRANSACTION
kehren Sie erst in den Status zurück, bevor diese gespeicherte Prozedur aufgerufen wurde, und belassen den vorhandenen Prozess als anderweitig gültig.
Wenn Sie weitere Informationen zu wünschen SAVE TRANSACTION
, lesen Sie bitte die Informationen in dieser Antwort:
Zurücksetzen, wenn 3 gespeicherte Prozeduren von einer gespeicherten Prozedur gestartet werden
Ein weiteres Problem SAVE TRANSACTION
ist eine Nuance des Verhaltens, wie auf der MSDN-Seite für SAVE TRANSACTION (Hervorhebung hinzugefügt) angegeben:
Doppelte Sicherungspunktnamen sind in einer Transaktion zulässig, aber eine ROLLBACK TRANSACTION-Anweisung, die den Sicherungspunktnamen angibt, setzt die Transaktion nur unter Verwendung dieses Namens auf die letzte SAVE TRANSACTION zurück.
Das heißt, Sie müssen sehr vorsichtig sein, um jedem Speicherpunkt in jeder gespeicherten Prozedur einen Namen zu geben, der für alle Speicherpunkte in allen gespeicherten Prozeduren eindeutig ist. Die folgenden Beispiele veranschaulichen diesen Punkt.
Dieses erste Beispiel zeigt, was passiert, wenn Sie den Namen des Speicherpunkts wiederverwenden. Nur der Speicherpunkt der niedrigsten Ebene wird zurückgesetzt.
IF (OBJECT_ID(N'tempdb..#SaveTranTestA') IS NOT NULL)
BEGIN
DROP TABLE #SaveTranTestA;
END;
CREATE TABLE #SaveTranTestA (SomeVal INT NOT NULL);
BEGIN TRAN; -- start level 1
SAVE TRANSACTION MySavePoint;
SELECT @@TRANCOUNT AS [TranCount]; -- 1
INSERT INTO #SaveTranTestA (SomeVal) VALUES (100);
BEGIN TRAN; -- start level 2
SAVE TRANSACTION MySavePoint;
SELECT @@TRANCOUNT AS [TranCount]; -- 2
INSERT INTO #SaveTranTestA (SomeVal) VALUES (200);
COMMIT; -- exit level 2
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestA;
-- 100
-- 200
ROLLBACK TRANSACTION MySavePoint; -- error occurred; undo actions up to this point
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestA;
-- 100
COMMIT; -- exit level 1
SELECT @@TRANCOUNT AS [TranCount]; -- 0
SELECT * FROM #SaveTranTestA;
-- 100
Dieses zweite Beispiel zeigt, was passiert, wenn Sie eindeutige Speicherpunktnamen verwenden. Der Speicherpunkt des gewünschten Levels wird zurückgesetzt.
IF (OBJECT_ID(N'tempdb..#SaveTranTestB') IS NOT NULL)
BEGIN
DROP TABLE #SaveTranTestB;
END;
CREATE TABLE #SaveTranTestB (SomeVal INT NOT NULL);
BEGIN TRAN; -- start level 1
SAVE TRANSACTION MySavePointUno;
SELECT @@TRANCOUNT AS [TranCount]; -- 1
INSERT INTO #SaveTranTestB (SomeVal) VALUES (100);
BEGIN TRAN; -- start level 2
SAVE TRANSACTION MySavePointDos;
SELECT @@TRANCOUNT AS [TranCount]; -- 2
INSERT INTO #SaveTranTestB (SomeVal) VALUES (200);
COMMIT; -- exit level 2
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestB;
-- 100
-- 200
ROLLBACK TRANSACTION MySavePointUno; --error occurred; undo actions up to this point
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestB;
-- <no rows>
COMMIT; -- exit level 1
SELECT @@TRANCOUNT AS [TranCount]; -- 0
SELECT * FROM #SaveTranTestB;
-- <no rows>