Как управлять вложенной транзакцией с помощью try catch
--Drop Table Tab1
Begin Transaction TR1;
Save Transaction TR1;
Create Table Tab1(f1 decimal(10,0));
Begin Transaction TR2
Save Transaction TR2
insert into Tab1 values(1);
Begin Transaction TR3;
Save Transaction TR3;
insert into Tab1 values(2);
Begin Try
insert into Tab1 values('OK');
Commit Transaction TR3;
END TRY
BEGIN Catch
print 'catch'
RollBack Transaction TR3;
End Catch
insert into Tab1 values(3);
Commit Transaction TR2
insert into Tab1 values(4);
Commit Transaction TR1;
--Commit Transaction;
select * from Tab1;
Drop Table Tab1
Select @@TRANCount
Происходит ошибка:
Сообщение 3931, уровень 16, состояние 1, строка 17 Текущая транзакция не может быть зафиксирована и не может быть откатлена до точки сохранения. Откатить всю транзакцию.
Как справиться с этим.
1 ответ
Когда возникают ошибки определенного типа, вы не можете выполнить откат до точки сохранения. См Martin Smith Ответ Martin Smith на откат транзакции до точки сохранения при сбое ALTER TABLE… ADD CONSTRAINT. То, как вы обнаруживаете это, чтобы проверить Xact_state()
,
Однако ваша проблема несколько иная, потому что вы также пытаетесь использовать вложенные транзакции. Вложенные транзакции на самом деле не работают в SQL, как мы ожидаем.
- Вы можете назвать только внешнюю транзакцию. Просмотреть транзакции (компонент Database Engine)
Например, это не с Cannot roll back TR2. No transaction or savepoint of that name was found.
НАЧАЛО СДЕЛКИ TR1; НАЧАЛО СДЕЛКИ TR2 ROLLBACK TRANSACTION TR2 COMMIT Транзакция TR1
Фиксация внутренних транзакций игнорируется ядром базы данных SQL Server
Недопустимо, чтобы параметр транзакция_имя оператора ROLLBACK TRANSACTION ссылался на внутренние транзакции набора именованных вложенных транзакций. название транзакции может ссылаться только на имя самой внешней транзакции
Пол С. Рэндал исследует это далее в мифе администратора баз данных SQL Server в день: (26/30) вложенные транзакции реальны
Лучшее, что вы можете сделать, это использовать вместо этого точки сохранения и проверить Xact_state в вашем улове и в конце.
BEGIN TRANSACTION tr1;
SAVE TRANSACTION tr2;
CREATE TABLE tab1
(
f1 DECIMAL(10, 0)
);
SAVE TRANSACTION tr3
INSERT INTO tab1
VALUES (1);
SAVE TRANSACTION tr4;
INSERT INTO tab1
VALUES (2);
BEGIN try
-- change the order of the follwoing two lines around to see the difference
INSERT INTO tab1 VALUES (1 / 0); --Results in a rollback to savepoint
INSERT INTO tab1 VALUES ('OK'); --Results in a complete rollback
COMMIT TRANSACTION tr4;
END try
BEGIN catch
IF Xact_state() = -1
BEGIN
PRINT 'rollback transaction no other work can be done'
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
PRINT 'rollback to savepoint'
ROLLBACK TRANSACTION tr4
END
END catch
IF Xact_state() > 0
BEGIN
INSERT INTO tab1
VALUES (3);
INSERT INTO tab1
VALUES (4);
COMMIT TRANSACTION tr1;
SELECT *
FROM tab1;
DROP TABLE tab1
END