Транзакция SQL Server 2008, требуется откат? - PullRequest
7 голосов
/ 22 октября 2010

У меня есть хранимая процедура, которая имеет операторы BEGIN TRANSACTION и COMMIT TRANSACTION.Внутри транзакции находится запрос на выборку WITH(XLOCK, ROWLOCK).

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

Мой вопрос заключается в том, должен ли я обернуть транзакцию в TRY / CATCH и откат, или это действительно не требуется, и все блокировки будут сняты автоматически, если транзакция завершится неудачно?Моя единственная проблема в том, что SQL не снимет все блокировки транзакции в случае сбоя транзакции.

Спасибо,

Том

Ответы [ 5 ]

8 голосов
/ 22 октября 2010

Гораздо проще:

set xact_abort on

Это приведет к автоматическому откату транзакции при возникновении ошибки.

Пример кода:

set xact_abort on
begin transaction
select 1/0
go
print @@trancount -- Prints 0

set xact_abort off
begin transaction
select 1/0
go
print @@trancount -- Prints 1

Если вы выполните второй сегмент несколько раз, вы увидите, что количество транзакций увеличится до 2,3,4 и т. Д. За один прогон первого сегмента сбрасываются все транзакции.

6 голосов
/ 22 октября 2010

Краткий ответ: Да.

Всякий раз, когда я использую BEGIN TRANSACTION, I всегда включает обработку ошибок использования и ROLLBACK. Последствия попадания в непредвиденную (и / или непредвиденную - вы не знаете, как может потребоваться изменить код в будущем) ситуацию, из-за которой открытая транзакция на производственном сервере слишком серьезна, чтобы этого не делать. *

В SQL Server 2000 и более ранних версиях необходимо использовать логику @@ Error. В SQL 2005 и более поздних версиях вы можете использовать синтаксис TRY ... CATCH ... (гораздо более высокий).

5 голосов
/ 21 октября 2012

Мне нравится подход Брэда, но он требует небольшой очистки, чтобы вы могли увидеть ошибку, вызвавшую проблему.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
3 голосов
/ 22 октября 2010

TRY/CATCH не требуется для снятия блокировки. Однако я думаю, что следующий шаблон будет полезен для большинства транзакций.

BEGIN TRY
    BEGIN TRAN
    ...
    IF (@@error <> 0)
       ROLLBACK TRAN
END TRY
BEGIN CATCH
    ROLLBACK TRAN
END CATCH
--BEGIN FINALLY (doesnt exist, which is why I commented it out)    
    IF (@@trancount > 0)
       COMMIT TRAN
--END FINALLY
1 голос
/ 10 июля 2014
begin transaction; -- you don't want to hit catch block if begin transaction will fail
begin try

     ... updates/inserts/selects ...

   commit transaction; -- the last statement in try code block is always commit
end try
begin catch
   rollback transaction; -- first step before other error handling code is rollback  transaction
   declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
   select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)),  @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
   raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
...