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


Ответы:


231

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

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

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


41
так почему он не включен по умолчанию?
Майк W

1
XACT_ABORT по-прежнему требуется, если у вас есть BEGIN TRY- BEGIN CATCHи ROLLBACKс BEGIN CATCHблоком в Sql?
user20358

1
@ user20358 BEGIN TRY- BEGIN CATCHне будет отлавливать такие вещи, как тайм-аут, возникающий в клиентском приложении, и некоторые ошибки SQL также невозможно отследить, оставляя вас с открытой транзакцией, которую вы не ожидаете.
Том Линт

37

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


9
За исключением тайм-аутов клиентов ... и я считаю, что SET XACT_ABORT более эффективен в SQL 2005, потому что поведение более предсказуемо: гораздо меньше ошибок прерывания пакета.
ГБН

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

4
@RemusRusanu Как еще вы справитесь с длительной синхронной операцией с базой данных?
Ян Бойд

5
Документация MSDN гласит: «XACT_ABORT должен быть включен для операторов модификации данных в неявной или явной транзакции против большинства поставщиков OLE DB, включая SQL Server. Единственный случай, когда этот параметр не требуется, - если поставщик поддерживает вложенные транзакции». msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Натан

4
«По моему мнению, SET XACT_ABORT ON был сделан устаревшим благодаря добавлению BEGIN TRY / BEGIN CATCH» - я вас слышу, но, пожалуйста, смотрите sommarskog.se/error_handling/Part1.html
Engineer

22

Цитирование 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 ON («INSERT INTO t2» не будет выполнен, и клиентское приложение вызовет исключение).

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


8

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


1

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.