Откат транзакции по ошибкам - PullRequest
2 голосов
/ 24 ноября 2011

У меня большой сгенерированный скрипт.Он имеет несколько пакетов (GO операторов).Первая строка: BEGIN TRAN

Если во время выполнения возникнут какие-либо ошибки, вызванные либо с помощью RAISERROR, либо с помощью SQL Server, я хочу откатить транзакцию.Я хочу, чтобы скрипт продолжал выполняться до самого конца, затем выполнял откат, а не прерывал выполнение, как только возникает какая-либо ошибка.

Проверка @@error <> 0 в конце скрипта кажется недостаточной, посколькуесли последний оператор в сценарии завершается успешно, @@ error будет 0, даже если предыдущие операторы не выполнялись.

Я не могу объявить @rollback BIT в самом начале, потому что сценарий сегментирован на несколько пакетов,и поэтому переменная выходит за рамки.

Я понимаю, что RAISERROR не означает, что моя транзакция будет откатана.

Любые предложения о наилучшем способе реализации этого в SQL2000 совместимым образом?

Ответы [ 2 ]

2 голосов
/ 24 ноября 2011

Вы всегда можете использовать SET CONTEXT_INFO для передачи «внеполосной» информации и прочитать ее позже, используя CONTEXT_INFO(). Если возникает ошибка, установите для контекстной информации значение, которое вы проверяете непосредственно перед фиксацией.

Это отвечает на ваш вопрос о том, как это сделать, но я действительно должен выразить свои сомнения по поводу , почему делает это в первую очередь. Так как одна из многих ошибок прервет транзакцию , в любом случае , поэтому вы можете слепо продолжить, полагая, что продолжить безопасно, и выполнить откат только для того, чтобы обнаружить, что откатывать нечего и весь ваш ошибочный сценарий после того, как исключение совершило , совершено . Во-вторых, для исключений, которые не отменяют транзакцию, все еще очень сомнительно выполнять какую-либо работу только для ее отката. Ваша просьба настолько непроста, что я не могу понять, действительно ли вы понимаете все последствия того, что вы делаете.

1 голос
/ 24 ноября 2011

Обычный способ - создать временную таблицу и использовать шаблонный код в конце каждой партии

begin tran
go

create table #errors (errorid int not null)
go

select 1/ 0

declare @error int
set @error = @@error
if @error <> 0 insert into #errors values (@error)  
go

select 1/ 1

declare @error int
set @error = @@error
if @error <> 0 insert into #errors values (@error)    
go

if exists (select * from #errors)
begin
    print 'rolling back transaction'
    select * from #errors
    rollback tran
end
else
begin
    print 'commit transaction'
    commit tran
end
go

if OBJECT_ID('tempdb..#errors') is not null
    drop table #errors
go
...