Nie SAVE TRANSACTION
. Nigdy nie znalazłem powodu do tego. Wiem, że niektórzy ludzie wolą to, ale we wszystkim, co kiedykolwiek zrobiłem w dowolnym miejscu, w którym pracowałem, pojęcie błędu występującego na dowolnym z zagnieżdżonych poziomów sugerowało, że wszystko, co zostało już wykonane, było nieprawidłowe. Korzystając z tej opcji SAVE TRANSACTION
, powracasz do stanu tuż przed wywołaniem tej procedury składowanej, pozostawiając istniejący proces jako inny ważny.
Jeśli chcesz uzyskać więcej informacji SAVE TRANSACTION
, zapoznaj się z informacjami w tej odpowiedzi:
Jak wycofać, gdy 3 procedury przechowywane są uruchamiane z jednej procedury przechowywanej
Kolejny problem z SAVE TRANSACTION
jest niuans jego zachowania, jak zauważono na stronie MSDN SAVE TRANSACTION (wyróżnienie dodane):
Zduplikowane nazwy punktów zapisu są dozwolone w transakcji, ale instrukcja ROLLBACK TRANSACTION, która określa nazwę punktu zapisu, zwróci transakcję tylko do najnowszej ZAPISZ TRANSAKCJĘ przy użyciu tej nazwy.
Oznacza to, że należy bardzo uważać, aby nadać każdemu Punktowi zapisu w każdej Procedurze składowanej unikalną nazwę we wszystkich Punktach zapisu we wszystkich Procedurach przechowywanych. Poniższe przykłady ilustrują ten punkt.
Ten pierwszy przykład pokazuje, co się stanie, gdy użyjesz ponownie nazwy punktu zapisu; wycofany zostanie tylko punkt zapisu najniższego poziomu.
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
Ten drugi przykład pokazuje, co dzieje się, gdy używasz unikatowych nazw punktów zapisu; Punkt zapisu żądanego poziomu jest wycofywany.
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>