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 ROLLBACK
içinde CATCH
bloğ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ü
COMMIT
olduğ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
COMMIT
kesilirken @@TRANCOUNT
altı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 TRAN
hiçbir ROLLBACK
işlem, işlemin tamamının tamamını vermemeniz dışında geri alınamaz .
- Daha açıkçası: Bir verilmesi
COMMIT
sı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 COMMIT
dikkate alınmaz ve sadece okunabilirlik için geçerlidir.
Bir ROLLBACK
isim vermeden yayınlanan her zaman TÜM işlemleri geri alma olacaktır.
ROLLBACK
Adı verilen bir yayın şunlardan birine karşılık gelmelidir:
- Adının alındığı
varsayılarak ilk işlem: SAVE TRAN
Aynı 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 TRAN
komutları 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 B
bir kez: "DML Sorgu 4 "'ü geri alır. @@TRANCOUNT
hala 2.
ROLLBACK TRAN B
iki kez: "DML Sorgu 4 "'ü geri alır ve sonra" B "için karşılık gelen bir kayıt noktası olmadığından hata verir. @@TRANCOUNT
hala 2.
ROLLBACK TRAN A
bir kez: "DML Sorgu 4" ve "DML Sorgu 3" geri alınacaktır. @@TRANCOUNT
hala 2.
ROLLBACK TRAN A
iki kez: "DML Sorgu 4", "DML Sorgu 3" ve "DML Sorgu 2" yi geri alır. @@TRANCOUNT
hala 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.
COMMIT
bir kez: @@TRANCOUNT
1'e iniyor.
COMMIT
bir kez ve sonra bir ROLLBACK TRAN B
kez: @@TRANCOUNT
1'e iner. Sonra "DML Sorgu 4 "'ü geri alır (COMMIT'in hiçbir şey yapmadığını ispatlar). @@TRANCOUNT
hala 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 @@TRANCOUNT
aynı değerde olmalıdır . Yani yapamazsın:
BEGIN TRAN
Arama / ebeveyn işleminde işlem yapmayı beklemek yerine, işlem yapmadan proc'a başla .
ROLLBACK
Proc @@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
/ ROLLBACK
en 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...CATCH
yapı 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 ROLLBACK
kendinizi aradığınız sürece bir sorun değildir . Bununla birlikte, bazen toplu iş iptali hataları olması durumunda veya OPENQUERY
uzak 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...CATCH
kapana 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...CATCH
yapı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...CATCH
SQL Server 2005'te sunulan yapı, neredeyse tüm durumları için test üzerinde hoş bir gelişme taşıma bir araç sağlar @@ERROR
toplu iptal hatalarla çok yardımcı olmadı her ifade, sonra.
TRY...CATCH
Ancak, yeni bir "devlet" tanıttı. Ne zaman değil kullanarak TRY...CATCH
yapısını etkin bir Hareketi olmasını ve bir hata oluşursa, o zaman alınabilir çeşitli yollar vardır:
XACT_ABORT OFF
ve deyim-iptal hatası: İşlem hala etkin ve işleme sonraki devam açıklamada varsa.
XACT_ABORT OFF
ve toplu iş iptali hatalarının çoğu: İşlem hala etkin ve işlem varsa bir sonraki toplu işlemle devam ediyor .
XACT_ABORT OFF
ve belirli toplu iş iptali hataları: İşlem geri alınır ve varsa işlem sonraki işle devam eder .
XACT_ABORT ON
ve 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ü CATCH
bloğa transfer eder . Ne zaman XACT_ABORT
, OFF
İşlem zamanın büyük çoğunluğunda hala aktif olacak COMMIT
ve 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_ABORT
olduğ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 ROLLBACK
ve SELECT
ifadeler. Bununla birlikte, bu "uncomittable" durumunda, İşlem, meydana gelen hata üzerine geri alındı ve bunun verilmesi ROLLBACK
yalnı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. CATCH
Sonucun -1
test 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 ON
olması mümkün olan tek devlet olmalı, bu yüzden test için eşit @@TRANCOUNT > 0
ve XACT_STATE() <> 0
eşdeğer görünüyor . Öte yandan, XACT_ABORT
bir OFF
ve aktif İşlem yoktur, o zaman ya bir devlet olması mümkündür 1
veya -1
içinde CATCH
düzenlenmesine olanak sağlayan blok COMMIT
yerine ROLLBACK
bir durumda düşünemiyorum, her ne kadar zaman birileri için ( isterdimCOMMIT
İşlemin yapılabilmesi durumunda). XACT_STATE()
Bir CATCH
blok içinde kullanım hakkında daha fazla bilgi ve araştırma XACT_ABORT ON
aş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
BEGIN
ve END
çevresine ihtiyacınız yokEXEC
spNewBilling3
bir hata atar, ancak rulo arkasına istemiyorsanızspNewBilling2
yaspNewBilling1
, o zaman sadece kaldırmak[begin|rollback|commit] transaction createSavebillinginvoice
danspSavesomename
.