Нет SAVE TRANSACTION
. Я никогда не нашел случая использовать это. Я знаю, что некоторые люди предпочитают это, но во всем, что я когда-либо делал в любом месте, где я работал, понятие ошибки, возникающей на любом из вложенных уровней, подразумевало, что любая работа, которая уже была сделана, была недействительной. При использовании SAVE TRANSACTION
вы возвращаетесь в состояние только перед вызовом этой хранимой процедуры, в результате чего существующий процесс остается действительным.
Если вы хотите получить более подробную информацию SAVE TRANSACTION
, ознакомьтесь с информацией в этом ответе:
Как выполнить откат при запуске 3 хранимых процедур из одной хранимой процедуры
Другая проблема, с SAVE TRANSACTION
которой он сталкивается - это нюанс его поведения, как отмечено на странице MSDN для SAVE TRANSACTION (выделение добавлено):
В транзакции допускаются повторяющиеся имена точек сохранения, но оператор ROLLBACK TRANSACTION, который задает имя точки сохранения, будет выполнять откат транзакции только до самой последней операции SAVE TRANSACTION с использованием этого имени.
Это означает, что вы должны быть очень осторожны, чтобы дать каждой точке сохранения в каждой хранимой процедуре имя, уникальное для всех точек сохранения во всех хранимых процедурах. Следующие примеры иллюстрируют эту точку зрения.
Этот первый пример показывает, что происходит при повторном использовании имени точки сохранения; откатывается только точка сохранения самого низкого уровня.
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
Этот второй пример показывает, что происходит, когда вы используете уникальные имена точек сохранения; Точка сохранения нужного уровня откатывается.
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>