2010-10-22 2 views
7

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

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

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

Спасибо,

Том

ответ

6

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

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

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

3

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 
8

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

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 и т.д. Один прогон первого сегмента сбрасывает все транзакции.

5

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

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 
1
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 
Смежные вопросы