Saklı yordamda "SET XACT_ABORT ON" kullanmanın faydası nedir?


Yanıtlar:


231

SET XACT_ABORT ONSQL Server'a tüm işlemin geri alınmasını ve bir çalışma zamanı hatası oluştuğunda toplu işlemi iptal etmesini bildirir. SQL Server'ın kendisi yerine istemci uygulamasında oluşan bir komut zaman aşımı gibi durumlarda sizi kapsar (varsayılan XACT_ABORT OFFayar kapsamında değildir ).

Bir sorgu zaman aşımı işlemi açık bırakacağından, açık işlemlerle SET XACT_ABORT ONyapılan tüm saklı yordamlarda (başka bir işlem yapmak için özel bir nedeniniz yoksa) açık bir işlemle bağlantı üzerinde çalışma yapan bir uygulamanın sonuçları felaket olduğu için önerilir.

Dan Guzman'ın Blogunda gerçekten harika bir genel bakış var ,


41
Öyleyse neden varsayılan olarak AÇIK değil?
Mike W

1
XACT_ABORT hala varsa gerekli mi BEGIN TRY- BEGIN CATCHve ROLLBACKbirlikte BEGIN CATCHSql bloğun?
user20358

1
@ user20358 BEGIN TRY- BEGIN CATCHistemci uygulamasında oluşan bir zaman aşımı gibi şeyleri yakalamaz ve bazı SQL hataları da görünmezdir ve sizi beklemeyeceğiniz açık bir işlem bırakır.
Tom Lint

37

Bence SET XACT_ABORT ON, SQL 2k5'e BEGIN TRY / BEGIN CATCH eklenmesi ile geçersiz kılındı. Transact-SQL'de istisna bloklarından önce hataları işlemek gerçekten zordu ve dengesiz prosedürler çok yaygındı (çıkışta girişe kıyasla farklı bir @@ TRANCOUNT olan prosedürler).

Transact-SQL özel durum işleme eklenmesi ile işlemleri düzgün bir şekilde dengelemek için garanti edilen doğru yordamları yazmak çok daha kolaydır. Örneğin, bu şablonu özel durum işleme ve iç içe işlemler için kullanıyorum :

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

Kurtarılabilir hatalar durumunda yalnızca kendi çalışmalarını geri alan atomik prosedürler yazmama izin veriyor.

Transact-SQL yordamlarının karşılaştığı ana sorunlardan biri veri saflığıdır : bazen alınan parametreler veya tablolardaki veriler basit yanlıştır, bu da yinelenen anahtar hataları, referans kısıtlama hataları, kısıtlama hatalarını kontrol eder vb. Sonuçta, bu tam olarak bu kısıtlamaların rolü, eğer bu veri saflığı hataları imkansız ve iş mantığı tarafından yakalansaydı, kısıtlamalar tamamen eski olurdu (etki için dramatik abartı eklendi). XACT_ABORT AÇIK ise, tüm bu hatalar istisnayı zarif bir şekilde işleyen istisna bloklarını kodlayabilmenin aksine tüm işlemin kaybolmasına neden olur. Tipik bir örnek bir INSERT yapmaya ve PK ihlali konusunda bir GÜNCELLEME'ye dönmeye çalışmaktır.


9
İstemci zaman aşımları dışında ... ve benim görüşüm SET XACT_ABORT SQL 2005'te daha etkilidir çünkü davranış daha tahmin edilebilir: çok daha az toplu iptal hatası.
gbn

7
Bir şekilde katılıyorum, ancak hata işlemimi tüm olasılıklar etrafında planlıyorum, çünkü bir komut zaman aşımı oluşursa suçu Geliştirici DBA olarak alacağımı biliyorum.
gbn

4
@RemusRusanu Uzun süreli, senkronize bir veritabanı işlemini başka nasıl halledersiniz?
Ian Boyd

5
MSDN belgelerinde: "SQL Server da dahil olmak üzere çoğu OLE DB sağlayıcısına karşı örtülü veya açık bir işlemde veri değiştirme ifadeleri için XACT_ABORT AÇIK olarak ayarlanmalıdır. Bu seçeneğin gerekli olmadığı tek durum, sağlayıcının iç içe geçmiş işlemleri desteklemesidir." msdn.microsoft.com/en-us/library/ms188792(v=sql.120).aspx
Nathan

4
"Bence SET XACT_ABORT ON, BEGIN TRY / BEGIN CATCH eklenmesiyle geçersiz kılındı
Reversed Engineer

22

MSDN'den alıntı :

SET XACT_ABORT AÇIK olduğunda, bir Transact-SQL deyimi bir çalışma zamanı hatası verirse, tüm işlem sonlandırılır ve geri alınır. SET XACT_ABORT KAPALI olduğunda, bazı durumlarda yalnızca hatayı yükselten Transact-SQL deyimi geri alınır ve işlem işlemeye devam eder.

Uygulamada bu, bazı ifadelerin başarısız olabileceği ve işlemin 'kısmen tamamlandığı' anlamına gelebileceği ve arayan için bu başarısızlığın bir işareti olmayabileceği anlamına gelir.

Basit bir örnek:

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

Bu kod, XACT_ABORT OFF ile 'başarıyla' yürütülür ve XACT_ABORT ON ile bir hata ile sonlanır ('INSERT INTO t2' yürütülmez ve istemci uygulaması bir istisna oluşturur).

Daha esnek bir yaklaşım olarak, her ifadeden sonra (eski okul) @@ HATA kontrol edebilir veya TRY ... CATCH bloklarını (MSSQL2005 +) kullanabilirsiniz. Şahsen bazı gelişmiş hata işlemeleri için hiçbir neden olmadığında XACT_ABORT'u AÇIK olarak ayarlamayı tercih ederim.


8

İstemci zaman aşımları ve bunları işlemek için XACT_ABORT kullanımı ile ilgili olarak, bence SqlClient gibi istemci API'larında zaman aşımına sahip olmanın en az bir iyi nedeni var ve bu, istemci uygulama kodunu SQL sunucu kodunda meydana gelen çıkmazlardan korumaktır. Bu durumda, istemci kodunda hata yoktur, ancak komutun sunucuda tamamlanmasını bekleyen sonsuza kadar kendini engellemekten korumak gerekir. Buna karşılık, istemci kodunu korumak için istemci zaman aşımlarının olması gerekiyorsa, XACT_ABORT ON'un sunucu kodunu istemcinin iptal etmesine karşı korumak zorundaysa, sunucu kodunun yürütülmesi istemcinin beklemek istediğinden daha uzun sürmesi durumunda.


1

İşlem yönetiminde, herhangi bir hatanın işlemin geri alınmasına neden olmasını sağlamak için kullanılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.