Яка вигода від використання “SET XACT_ABORT ON” у збереженій процедурі?


Відповіді:


231

SET XACT_ABORT ONдоручає SQL Server відкатати всю транзакцію та перервати партію, коли виникає помилка під час виконання. Він охоплює вас у випадках, як час очікування команди, що виникає на клієнтській програмі, а не в самому SQL Server (який не охоплюється XACT_ABORT OFFналаштуваннями за замовчуванням .)

Оскільки час очікування запиту залишить транзакцію відкритою, SET XACT_ABORT ONрекомендується в усіх збережених процедурах із явними транзакціями (якщо у вас немає конкретної причини зробити інше), оскільки наслідки програми, яка виконує роботу над з'єднанням з відкритою транзакцією, згубні.

У блозі Дена Гузмана дійсно чудовий огляд ,


41
так чому він за замовчуванням не вмикається?
Майк Ш

1
Ще потрібен XACT_ABORT, якщо у вас є BEGIN TRY- BEGIN CATCHі ROLLBACKз BEGIN CATCHблоком у Sql?
користувач20358

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 на порушення ПК.


9
За винятком термінів очікування клієнтів ... і, на мій погляд, SET XACT_ABORT є більш ефективним у SQL 2005, оскільки поведінка є більш передбачуваною: набагато менше помилок, що переривають партію.
gbn

7
Я дещо погоджуюсь, але я планую свою помилку щодо вирішення всіх можливих випадків, оскільки я знаю, що я буду винуватий як розробник DBA, якщо відбудеться тайм-аут команди.
gbn

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
інженер, що

22

Цитуючи 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" не буде виконано, і клієнтська програма створить виняток).

Як більш гнучкий підхід, ви можете перевірити @@ ПОМИЛКУ після кожного твердження (стара школа) або використовувати блоки 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.