В чем преимущество использования SET XACT_ABORT ON
в хранимой процедуре?
В чем преимущество использования "SET XACT_ABORT ON" в хранимой процедуре?
Ответ 1
SET XACT_ABORT ON
указывает SQL Server откатить всю транзакцию и прервать пакет при возникновении ошибки времени выполнения. Он охватывает вас в случаях, таких как тайм-аут команды, происходящий в клиентском приложении, а не в самом SQL Server (который не покрывается настройкой по умолчанию XACT_ABORT OFF
.)
Поскольку тайм-аут запроса оставит транзакцию открытой, SET XACT_ABORT ON
рекомендуется во всех хранимых процедурах с явными транзакциями (если только у вас нет конкретной причины делать это иначе) в качестве последствий приложения, выполняющего работу над соединением с открытым транзакции катастрофичны.
Там действительно отличный обзор Блог Dan Guzman,
Ответ 2
На мой взгляд, SET XACT_ABORT ON был устаревшим, добавив BEGIN TRY/BEGIN CATCH в SQL 2k5. До блоков исключений в Transact-SQL было очень сложно обрабатывать ошибки, и неуравновешенные процедуры были слишком распространены (процедуры, у которых при выходе был выход другой @@TRANCOUNT по сравнению с входом).
С добавлением обработки исключений Transact-SQL гораздо проще написать правильные процедуры, гарантирующие правильную балансировку транзакций. Например, я использую этот шаблон для обработки исключений и вложенных транзакций:
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
go
Это позволяет мне писать атомные процедуры, которые откатываются только от собственной работы в случае восстанавливаемых ошибок.
Одной из основных проблем, с которой сталкиваются процедуры Transact-SQL, является чистота данных: иногда полученные параметры или данные в таблицах просто неверны, что приводит к дублированию ключевых ошибок, референциальным ограничениям, проверке ошибок ограничения и т.д. И т.д. В конце концов, именно роль этих ограничений, если бы эти ошибки чистоты данных были бы невозможны и все пойманы бизнес-логикой, ограничения были бы устаревшими (драматическое преувеличение добавлено для эффекта). Если XACT_ABORT включен, то все эти ошибки приводят к потере всей транзакции, в отличие от возможности кодировать блоки исключений, которые обрабатывают исключение изящно. Типичным примером является попытка сделать INSERT и вернуться к UPDATE при нарушении PK.
Ответ 3
Цитирование MSDN:
Когда SET XACT_ABORT включен, если оператор Transact-SQL вызывает ошибку во время выполнения, вся транзакция завершается и откатывается. Когда SET XACT_ABORT выключен, в некоторых случаях только оператор Transact-SQL, который поднял эту ошибку, откатывается назад, и транзакция продолжает обработку.
На практике это означает, что некоторые из инструкций могут выйти из строя, оставив транзакцию "частично завершенной", и не может быть никаких признаков этой ошибки для вызывающего.
Простой пример:
INSERT INTO t1 VALUES (1/0)
INSERT INTO t2 VALUES (1/1)
SELECT 'Everything is fine'
Этот код выполнил бы "успешно" с XACT_ABORT OFF и завершит с ошибкой с XACT_ABORT ON ( "INSERT INTO t2" не будет выполнен, а клиентское приложение вызовет исключение).
В качестве более гибкого подхода вы можете проверить @@ERROR после каждого заявления (старая школа) или использовать блоки TRY... CATCH (MSSQL2005 +). Лично я предпочитаю устанавливать XACT_ABORT ON всякий раз, когда нет причин для некоторой расширенной обработки ошибок.
Ответ 4
Что касается тайм-аутов клиентов и использования XACT_ABORT для их обработки, по моему мнению, есть хотя бы одна очень веская причина иметь тайм-ауты в клиентских API, таких как SqlClient, и это защищать код клиентского приложения от тупиков, возникающих в коде SQL-сервера. В этом случае клиентский код не имеет ошибки, но должен защитить его от блокировки навсегда, ожидая завершения команды на сервере. Поэтому, наоборот, если клиентские тайм-ауты должны существовать для защиты клиентского кода, XACT_ABORT ON должен защищать код сервера от прерываний клиента, в случае, если серверный код занимает больше времени, чем клиент готов ждать.
Ответ 5
Он используется в управлении транзакциями, чтобы гарантировать, что любые ошибки приведут к откату транзакции.