3 saklı prosedür bir saklı prosedürden başlatıldığında geri alma


23

İçlerinde yalnızca 3 saklı yordam yürüten saklı yordam var. Master SP başarılı olduğunda saklamak için sadece 1 parametre kullanıyorum.

İlk saklı yordam ana saklı yordamda düzgün çalışıyorsa ancak 2. saklı yordam başarısız olursa, otomatik olarak ana SP'deki tüm SP'leri geri alır mı yoksa bazı komutlar mı vermeliyim?

İşte benim prosedürüm:

CREATE PROCEDURE [dbo].[spSavesomename] 
    -- Add the parameters for the stored procedure here

    @successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
    begin Try
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

   BEGIN 

   EXEC [dbo].[spNewBilling1]

   END

   BEGIN 

   EXEC [dbo].[spNewBilling2]

   END

   BEGIN 

   EXEC [dbo].[spNewBilling3]

   END 

   set @successful  = 1

   end Try

    begin Catch
        rollback transaction createSavesomename
        insert into dbo.tblErrorMessage(spName, errorMessage, systemDate) 
             values ('spSavesomename', ERROR_MESSAGE(), getdate())

        return
    end Catch
commit transaction createSavesomename
return
END

GO

Eğer spNewBilling3bir hata atar, ancak rulo arkasına istemiyorsanız spNewBilling2ya spNewBilling1, o zaman sadece kaldırmak [begin|rollback|commit] transaction createSavebillinginvoicedan spSavesomename.
Mike

Yanıtlar:


56

Söz konusu gösterilen tek kod göz önüne alındığında, ve üç alt procs hiçbirinin varsayarak herhangi bir açık işlem taşınması, o zaman evet, üç alt procs herhangi bir hata yakalanacak ve ROLLBACKiçinde CATCHbloğun hepsi geri döner işin.

AMA burada işlemleri hakkında dikkat edilmesi gereken bazı şeyler (en azından SQL Server'da):

  • Kaç tane arama yaparsanız yapın , yalnızca bir gerçek işlem vardır (birincisi).BEGIN TRAN

    • (Burada yaptığımız gibi) Bir işlem adlandırabilirsiniz ve bu ad günlüklerde görünecektir, ancak (yine ilk biridir çünkü sadece ilk / en dış işlem için anlamı vardır adlandırma işlem).
    • Her çağrıldığında BEGIN TRAN, adlandırılmış olsun veya olmasın, işlem sayacı 1 ile artırılır.
    • Yaparak mevcut seviyeyi görebilirsiniz SELECT @@TRANCOUNT;
    • 2 ya da üstü COMMITolduğunda verilen herhangi bir komut @@TRANCOUNT, bir defada bir işlem sayacını düşürmekten başka bir şey yapmaz.
    • Bir kadar hiçbir şey şimdiye kadar kararlıdır COMMITkesilirken @@TRANCOUNTaltındadır1
    • Sadece yukarıdaki bilgilerin açıkça belirtilmediği durumlarda: işlem seviyesine bakılmaksızın, işlemlerin gerçek iç içe geçmesi yoktur.
  • Puanları kaydet , işlem içinde geri alınabilecek bir alt çalışma grubu oluşturmaya izin verir .

    • Kaydetme noktaları SAVE TRAN {save_point_name}komutla oluşturulur / işaretlenir
    • Puanları kaydet , tüm işlem geri alınmadan geri alınabilecek iş alt kümesinin başlangıcını işaretler .
    • Kaydetme noktası adlarının benzersiz olması gerekmez, ancak aynı adı bir kereden fazla kullanmak hala farklı kaydetme noktaları oluşturur.
    • Kaydet noktaları olabilir iç içe.
    • Puan kazanma taahhüt edilemez.
    • Kaydetme noktaları üzerinden geri alınabilir ROLLBACK {save_point_name}. (aşağıda daha fazlası)
    • Bir kaydetme noktasını geri almak, geri çevrildikten sonra oluşturulan tüm kaydetme noktaları dahil olmak üzere en son çağrıdan sonra gerçekleşen çalışmaları SAVE TRAN {save_point_name}geri alır (bu nedenle "yuvalama").
    • Bir kaydetme noktasını geri almanın işlem sayısı / düzeyi üzerinde hiçbir etkisi yoktur
    • İlk işlemden önce yapılan SAVE TRANhiçbir ROLLBACKişlem, işlemin tamamının tamamını vermemeniz dışında geri alınamaz .
    • Daha açıkçası: Bir verilmesi COMMITsırasında @@TRANCOUNT(yine 1'in üzerinde işlem seviyeleri yapmak sayaç dışında mevcut değildir çünkü) 2 veya yukarıda yer almaktadır, kaydetme noktaları üzerinde hiçbir etkisi yoktur.
  • Belirli adlandırılmış işlemleri taahhüt edemezsiniz. Birlikte verilenler ise "isim" işlemi COMMITdikkate alınmaz ve sadece okunabilirlik için geçerlidir.

  • Bir ROLLBACKisim vermeden yayınlanan her zaman TÜM işlemleri geri alma olacaktır.

  • ROLLBACKAdı verilen bir yayın şunlardan birine karşılık gelmelidir:

    • Adının alındığı
      varsayılarak ilk işlem: SAVE TRANAynı işlem adına sahip bir adın çağrılmadığı varsayılırsa , TÜM işlemleri geri alır.
    • Bir "kaydetme noktası" (yukarıda açıklanmıştır):
      Bu davranış, en son SAVE TRAN {save_point_name} çağrıldığından bu yana yapılan tüm değişiklikleri "geri alır" .
    • İlk işlem a) isminde ve b) isminde SAVE TRANkomutları verilmişse, bu işlem adının her bir ROLLBACK'ı, bu addan geriye kalana kadar her kayıt noktasını geri alır. Bundan sonra, bu isimde verilen bir ROLLBACK TÜM işlemleri geri alır.
    • Örneğin, aşağıdaki komutların gösterilen sırada çalıştırıldığını varsayın:

      BEGIN TRAN A -- @@TRANCOUNT is now 1
      -- DML Query 1
      SAVE TRAN A
      -- DML Query 2
      SAVE TRAN A
      -- DML Query 3
      
      BEGIN TRAN B -- @@TRANCOUNT is now 2
      SAVE TRAN B
      -- DML Query 4

      Şimdi, eğer sorun çıkarırsanız (aşağıdaki senaryoların her biri birbirinden bağımsızdır):

      • ROLLBACK TRAN Bbir kez: "DML Sorgu 4 "'ü geri alır. @@TRANCOUNThala 2.
      • ROLLBACK TRAN Biki kez: "DML Sorgu 4 "'ü geri alır ve sonra" B "için karşılık gelen bir kayıt noktası olmadığından hata verir. @@TRANCOUNThala 2.
      • ROLLBACK TRAN Abir kez: "DML Sorgu 4" ve "DML Sorgu 3" geri alınacaktır. @@TRANCOUNThala 2.
      • ROLLBACK TRAN Aiki kez: "DML Sorgu 4", "DML Sorgu 3" ve "DML Sorgu 2" yi geri alır. @@TRANCOUNThala 2.
      • ROLLBACK TRAN Aüç kez: "DML Sorgu 4", "DML Sorgu 3" ve "DML Sorgu 2" geri alınacaktır. Sonra tüm işlemi geri alır (geriye kalanların tümü "DML Sorgu 1" idi). @@TRANCOUNTşimdi 0.
      • COMMITbir kez: @@TRANCOUNT1'e iniyor.
      • COMMITbir kez ve sonra bir ROLLBACK TRAN Bkez: @@TRANCOUNT1'e iner. Sonra "DML Sorgu 4 "'ü geri alır (COMMIT'in hiçbir şey yapmadığını ispatlar). @@TRANCOUNThala 1.
  • İşlem isimleri ve kaydetme isimleri:

    • 32 karaktere kadar olabilir
    • Örnek düzeyinde veya Veri Tabanı düzeyinde Harmanlamalardan bağımsız olarak, ikili bir Harmanlamaya (halihazırda belgelerde belirtilen büyük / küçük harfe duyarlı değildir) sahip olarak kabul edilir.
    • Ayrıntılar için lütfen aşağıdaki yazının İşlem İsimleri bölümüne bakın: Bir Adında Neler Var ? : T-SQL Tanımlayıcılarının Kaçık Dünyası İçinde
  • Saklı bir prosedür, başlı başına gizli bir işlem değildir. Açık bir işlem başlatılmadıysa, her sorgu gizli bir işlemdir. Bu nedenle, tek bir sorgular etrafında yapılan açık işlemlerin, programlı bir neden olmadıkça gerekli olmadığına ROLLBACK, aksi halde sorgudaki herhangi bir hata o sorgunun otomatik olarak geri alınmasına neden olur.

  • Saklı yordam çağırırken, çağrıldığı zamankiyle @@TRANCOUNTaynı değerde olmalıdır . Yani yapamazsın:

    • BEGIN TRANArama / ebeveyn işleminde işlem yapmayı beklemek yerine, işlem yapmadan proc'a başla .
    • ROLLBACKProc @@TRANCOUNT, 0'a döneceği için çağrılmadan önce açık bir işlem başlatıldıysa sorunu çözemezsiniz .

    İşlem sayımı, başlangıçtan daha yüksek veya daha düşük olan, saklı bir yordamdan çıkarsanız, aşağıdakine benzer bir hata alırsınız:

    Mesaj 266, Seviye 16, Durum 2, İşlemci Adınız Prosedürü, Satır 0 EXECUTE'den
    sonraki işlem sayısı, BEGIN ve COMMIT deyimlerinin uyuşmadığını gösterir. Önceki sayı = X, geçerli sayı = Y

  • Tablo Değişkenleri, normal değişkenler gibi, işlemlerle bağlı değildir.


Bağımsız olarak çağrılabilen (ve dolayısıyla işlemle işlem yapmayı gerektirebilir) veya başka işlemlerden (bu nedenle işlemle işlem yapmanıza gerek kalmadan) çağrılan işlemlerde işlem ele alma işlemine ilişkin olarak: Bu, birkaç farklı yolla gerçekleştirilebilir.

Şimdi birkaç yıldır elimden geldiğince iyi çalıştığı gözüküyor, sadece BEGIN/ COMMIT/ ROLLBACKen dış katmandan geçiyor. Alt işlemler, sadece işlem komutlarını atlar. Her bir prosese ne koyduğumun altını çizdim.

  • Her bir işlemin başında DECLARE @InNestedTransaction BIT;
  • Basit yerine, yapın BEGIN TRAN:

    IF (@@TRANCOUNT = 0)
    BEGIN
       SET @InNestedTransaction = 0;
       BEGIN TRAN; -- only start a transaction if not already in one
    END;
    ELSE
    BEGIN
       SET @InNestedTransaction = 1;
    END;
  • Basit yerine, yapın COMMIT:

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
       COMMIT;
    END;
  • Basit yerine, yapın ROLLBACK:

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
       ROLLBACK;
    END;

Bu yöntem, işlemin SQL Server'da başlatılıp başlatılmadığına veya uygulama katmanında başlatılmış olmasına bakılmaksızın aynı şekilde çalışmalıdır.

Bu İşlemin TRY...CATCHyapı içerisinde ele alınmasının tamamı için lütfen aşağıdaki DBA.SE sorusuna verilen cevabımı inceleyiniz: İşlemi C # Kodunda ve saklı prosedürde işlem yapmamız gerekiyor mu ?


“Temel bilgilerin” ötesine geçerek, dikkat edilmesi gereken bazı işlem nüansları vardır:

  • Varsayılan olarak, İşlemler, çoğu zaman, bir hata oluştuğunda otomatik olarak geri alınmaz / iptal edilmez. Bu, genellikle uygun hata işlemenin olduğu ve ROLLBACKkendinizi aradığınız sürece bir sorun değildir . Bununla birlikte, bazen toplu iş iptali hataları olması durumunda veya OPENQUERYuzak sistemde (veya genel olarak Bağlantılı Sunucular) kullanılırken ve bir hata oluşursa işler karmaşıklaşır . Çoğu hata kullanılarak TRY...CATCHkapana kısılabilirken, bu şekilde kapana kısılmayan iki şey var (şu anda hangisinin olduğunu hatırlayamıyorum - olsa da). Bu durumlarda, SET XACT_ABORT ONİşlemi doğru bir şekilde geri almak için kullanmanız gerekir .

    SET XACT_ABORT ON SQL Server neden olur hemen (bir aktifse) geriye kıvrılan herhangi İşlem ve toplu iptal olursa herhangi hata oluşur. Bu ayar, TRY...CATCHyapıyı tanıtan SQL Server 2005'ten önce mevcuttu . Çoğu zaman, TRY...CATCHçoğu durumu ele alır ve bu yüzden çoğunlukla ihtiyacı ortadan kaldırır XACT_ABORT ON. Bununla birlikte, kullanırken OPENQUERY(ve şu anda hatırlayamadığım bir senaryo daha varsa), yine de kullanmanız gerekecektir SET XACT_ABORT ON;.

  • Bir Tetikleyicinin İçi XACT_ABORT, dolaylı olarak ayarlanır ON. Bu , Tetikleyici içindeki tüm DML deyimini iptal etmek için Tetikleyici içindeki herhangi bir hataya neden olur .

  • Özellikle İşlemler kullanırken her zaman uygun hata işlemelere sahip olmalısınız. TRY...CATCHSQL Server 2005'te sunulan yapı, neredeyse tüm durumları için test üzerinde hoş bir gelişme taşıma bir araç sağlar @@ERRORtoplu iptal hatalarla çok yardımcı olmadı her ifade, sonra.

    TRY...CATCHAncak, yeni bir "devlet" tanıttı. Ne zaman değil kullanarak TRY...CATCHyapısını etkin bir Hareketi olmasını ve bir hata oluşursa, o zaman alınabilir çeşitli yollar vardır:

    • XACT_ABORT OFFve deyim-iptal hatası: İşlem hala etkin ve işleme sonraki devam açıklamada varsa.
    • XACT_ABORT OFFve toplu iş iptali hatalarının çoğu: İşlem hala etkin ve işlem varsa bir sonraki toplu işlemle devam ediyor .
    • XACT_ABORT OFFve belirli toplu iş iptali hataları: İşlem geri alınır ve varsa işlem sonraki işle devam eder .
    • XACT_ABORT ONve herhangi bir hata: İşlem geri alınır ve varsa sonraki işlemle işleme devam edilir .


    NASIL, kullanırken TRY...CATCH, parti iptali hataları, partiyi iptal etmez, bunun yerine kontrolü CATCHbloğa transfer eder . Ne zaman XACT_ABORT, OFFİşlem zamanın büyük çoğunluğunda hala aktif olacak COMMITve büyük olasılıkla ya da büyük olasılıkla ihtiyacınız olacak ROLLBACK. Ancak, belirli bir toplu iş iptali ile ilgili hatalarla (ne gibi OPENQUERY) karşılaştığında, ya da ne zaman XACT_ABORTolduğunda ON, İşlem yeni bir durumda “uygunsuz” olacaktır. Bu durumda yapamazsınız COMMIT, herhangi bir DML işlemi yapamazsınız. Yapabileceğin tek şey ROLLBACKve SELECTifadeler. Bununla birlikte, bu "uncomittable" durumunda, İşlem, meydana gelen hata üzerine geri alındı ​​ve bunun verilmesi ROLLBACKyalnızca bir formalite, ancak yapılması gereken bir işlemdir .

    Bir İşlemin etkin, uygun olmayan veya mevcut olmadığını belirlemek için XACT_STATE adlı bir işlev kullanılabilir. CATCHSonucun -1test edilmek yerine (yani uygun olmadığının) olup olmadığını belirlemek için bu fonksiyonu blokta kontrol etmeniz önerilir (en azından bazıları tarafından ) @@TRANCOUNT > 0. Ancak bununla birlikte XACT_ABORT ONolması mümkün olan tek devlet olmalı, bu yüzden test için eşit @@TRANCOUNT > 0ve XACT_STATE() <> 0eşdeğer görünüyor . Öte yandan, XACT_ABORTbir OFFve aktif İşlem yoktur, o zaman ya bir devlet olması mümkündür 1veya -1içinde CATCHdüzenlenmesine olanak sağlayan blok COMMITyerine ROLLBACKbir durumda düşünemiyorum, her ne kadar zaman birileri için ( isterdimCOMMITİşlemin yapılabilmesi durumunda). XACT_STATE()Bir CATCHblok içinde kullanım hakkında daha fazla bilgi ve araştırma XACT_ABORT ONaşağıdaki DBA.SE sorusuna cevabımda bulunabilir: XACT_ABORT ON olarak ayarlandığında hangi durumlarda CATCH bloğunun içinden bir işlem yapılabilir? . Bazı senaryolarda XACT_STATE()yanlış şekilde geri dönmesine neden olan küçük bir hata olduğunu lütfen unutmayın 1: XACT_STATE (), SELECT'te bazı sistem değişkenleriyle birlikte, ancak FROM deyimi olmadan kullanıldığında 1 değerini döndürür.


Orijinal kodla ilgili notlar:

  • Herhangi bir işe yaramadığı için işleme verilen adı kaldırabilirsiniz.
  • Her aramaya BEGINve ENDçevresine ihtiyacınız yokEXEC

2
Bu gerçekten iyi, iyi bir cevap.
McNets

1
Vay, bu kapsamlı bir cevap! Teşekkür ederim! Aşağıdaki sayfada BTW dos, Try tarafından yakalanmadığınız hatalara dikkat edin ... Catch? (Başlığı "bir TRY ... CATCH Construct etkilenmez Hatalar" altında? Technet.microsoft.com/en-us/library/ms175976(v=sql.110).aspx
jrdevdba

1
@jrdevdba Teşekkürler :-). Ve hoşgeldin. Sıkışmayan hatalarla ilgili olarak, bu ikisini kastediyordum: Compile errors, such as syntax errors, that prevent a batch from runningve Errors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.. Ancak, çok sık gerçekleşmezler ve böyle bir durum bulduğunuzda, onu (koddaki bir hata ise) düzeltin ya da bunu alt-üste ( EXECya da sp_executesql) TRY...CATCHtuzağa düşürecek şekilde yerleştirin.
Solomon Rutzky

2

Evet, ana saklı yordamınızın catch deyimindeki herhangi bir hata geri alma kodu yürütülürse, herhangi bir doğrudan ifade ile veya içindeki yuvalanmış saklı yordamlarınız aracılığıyla gerçekleştirilen tüm işlemleri geri alır.

İç içe geçmiş saklı yordamlarınızda açık bir işlem uygulamamış olsanız bile, bu saklı yordamlar örtük işlemi kullanacaktır ve tamamlanma işlemi gerçekleştirecektir. Ana saklı yordam başarısız olursa ve işlem geri alınırsa, tüm eylemleri bu yuvalanmış saklı yordamlarla geri alma.

İşlem, her zaman en dış işlemin sonunda gerçekleştirilen eyleme bağlı olarak gerçekleştirilir veya geri alınır. Dış işlem gerçekleştirilirse, iç içe geçmiş işlemler de işlenir. Dış işlem geri alınırsa, o zaman iç işlemlerin ayrı ayrı yapılıp yapılmadığına bakılmaksızın tüm iç işlemler de geri alınır.

Başvuru için http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx

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.