В чем преимущество использования "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

Он используется в управлении транзакциями, чтобы гарантировать, что любые ошибки приведут к откату транзакции.