В чем преимущество использования «SET XACT_ABORT ON» в хранимой процедуре? - PullRequest
159 голосов
/ 19 июля 2009

В чем преимущество использования SET XACT_ABORT ON в хранимой процедуре?

Ответы [ 5 ]

204 голосов
/ 19 июля 2009

SET XACT_ABORT ON указывает SQL Server откатить всю транзакцию и прервать пакет при возникновении ошибки во время выполнения. Он охватывает вас в таких случаях, как тайм-аут команды, возникающий в клиентском приложении, а не в самом SQL Server (на который не распространяется настройка по умолчанию XACT_ABORT OFF.)

Так как тайм-аут запроса оставит транзакцию открытой, SET XACT_ABORT ON рекомендуется во всех хранимых процедурах с явными транзакциями (если у вас нет особой причины поступать иначе) в качестве последствий приложения, выполняющего работу над соединением с открытым транзакции катастрофичны.

Там действительно отличный обзор Блог Дэна Гузмана ,

32 голосов
/ 19 июля 2009

По моему мнению, 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.

20 голосов
/ 19 июля 2009

Цитирование MSDN :

Когда SET XACT_ABORT установлен в ON, если инструкция Transact-SQL вызывает ошибку во время выполнения, вся транзакция завершается и откатывается. Когда SET XACT_ABORT установлен в OFF, в некоторых случаях откатывается только инструкция Transact-SQL, которая вызвала ошибку, и транзакция продолжает обрабатываться.

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

Простой пример:

INSERT INTO t1 VALUES (1/0)    
INSERT INTO t2 VALUES (1/1)    
SELECT 'Everything is fine'

Этот код будет выполнен «успешно» с выключенным XACT_ABORT и завершится с ошибкой с включенным XACT_ABORT («INSERT INTO t2» не будет выполнен, и клиентское приложение вызовет исключение).

В качестве более гибкого подхода вы можете проверять @@ ERROR после каждого оператора (старая школа) или использовать блоки TRY ... CATCH (MSSQL2005 +). Лично я предпочитаю устанавливать XACT_ABORT ON всякий раз, когда нет причин для какой-либо сложной обработки ошибок.

4 голосов
/ 06 февраля 2013

Что касается тайм-аутов клиентов и использования XACT_ABORT для их обработки, по моему мнению, есть, по крайней мере, одна очень веская причина иметь тайм-ауты в клиентских API, таких как SqlClient, и защищать код клиентского приложения от тупиков, возникающих на SQL-сервере. код. В этом случае в клиентском коде нет ошибки, но он должен сам защитить себя от блокировки, ожидающей завершения команды на сервере. И наоборот, если для защиты клиентского кода должны существовать тайм-ауты клиента, то XACT_ABORT ON должен защищать код сервера от аварий клиента, в случае, если выполнение кода сервера занимает больше времени, чем клиент готов ждать.

1 голос
/ 19 июля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...