2016-05-06 20 views
6

Daha fazla TSQL öğrenen bir C# geliştiricisiyim. Böyle bir senaryo yazdım:Bir hareket denemesi gerektiriyor mu?

begin transaction 
--Insert into several tables 
end transaction 

Ama bunun iyi bir fikir değildi ve böyle bir şey kullanmak söylendi:

BEGIN TRANSACTION; 

BEGIN TRY 
    -- Generate a constraint violation error. 
    DELETE FROM Production.Product 
    WHERE ProductID = 980; 
END TRY 
BEGIN CATCH 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber 
     ,ERROR_SEVERITY() AS ErrorSeverity 
     ,ERROR_STATE() AS ErrorState 
     ,ERROR_PROCEDURE() AS ErrorProcedure 
     ,ERROR_LINE() AS ErrorLine 
     ,ERROR_MESSAGE() AS ErrorMessage; 

    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION; 
END CATCH; 

IF @@TRANCOUNT > 0 
    COMMIT TRANSACTION; 
GO 

ikinci örnek daha doğru olduğunu neden görmüyorum . Birincisi aynı şekilde çalışmıyor mu? İlk olarak tüm tabloları güncelleyecek ya da hiç olmayacak gibi görünüyor mu? İşlemden önce neden @@TRANCOUNT numaralı telefonu kontrol etmenin gerekli olmadığını anlamıyorum.

+1

Seninle aynı argümanı yapar. Ek olarak size önerilen try/catch kalıbı, try/squelch dediğim bir anti-pattern'tir. Yakalar ve hata yapar ve sessizce ilerler. Bu hatalarla uğraşmıyor, onları bastırıyor. Bir işlem için try/catch bloğu gerekli değildir. Özellikle büyük olasılıkla her zamankinden çözecek çok daha fazla sorunlara neden olur bir try/catch kullanarak, bir tetikleyici olup olmadığını. –

+2

İkinci örnekte herhangi bir şey varsa, bu işlem, catchtan sonra değil, try bloğunun içinde olmalıdır ... sanırım – Kritner

cevap

4

Kontrol işlemlerinizi işlemek için toplu sonuna gitmek için beklemeyin, siz deneyin blok içine ve sadece gerçek deyimi önce bir kez sadece İşlem açın Ve derhal bunu taahhüt. Bulunduğunuz Blok deneyin ve bir şey kontrolü CATCH blok atlar yanlış giderse sen, bir işlem açtıktan sonra

, Basitçe orada İşlem geri ve gerektiğinde işleme başka hatayı yapmak.

Aslında @@ ROWCOUNT işlevini kullanarak herhangi bir açık işlem için kontrol hareketi geri alma önce, Gerçekten bu senaryoda çok sense yapmak doesnt biraz çeki ekledik. Param değerlerini ve diğer şeyleri kontrol etmek gibi bir işlemi açmadan ve doğrulama kontrollerinden herhangi biri başarısız olursa, try bloğunda hata artırmadan önce, try bloğunuzda bazı validasyon kontrolleri yaptığınızda daha yararlıdır. Bu durumda kontrol, blok bloğa atlayacaktır. Bir işlemi bile açmadan herhangi bir açık işlem olup olmadığını kontrol edebilir ve açık olanlar varsa geri dönebilirsiniz. Durumunuzda olduğu gibi, işleminiz içinde bir şeyler ters gitmedikçe, catch işlemini engelleyemeyeceğiniz için açık bir işlemi kontrol etmeniz gerekmez.

BEGIN TRY 

    BEGIN TRANSACTION 
    -- Multiple Inserts 
    INSERT INTO.... 
    INSERT INTO.... 
    INSERT INTO.... 
COMMIT TRANSACTION 
    PRINT 'Rows inserted successfully...' 

END TRY 

BEGIN CATCH 
    IF (@@TRANCOUNT > 0) 
    BEGIN 
     ROLLBACK TRANSACTION 
     PRINT 'Error detected, all changes reversed' 
    END 
    SELECT 
     ERROR_NUMBER() AS ErrorNumber, 
     ERROR_SEVERITY() AS ErrorSeverity, 
     ERROR_STATE() AS ErrorState, 
     ERROR_PROCEDURE() AS ErrorProcedure, 
     ERROR_LINE() AS ErrorLine, 
     ERROR_MESSAGE() AS ErrorMessage 
END CATCH 
+0

Sanırım, @@ TranCount'u, açıklamalarınızda değil, @@ RowCount'u kastettiniz. Ayrıca genel bir mesajla _ dahil etmek tereddüt ediyorum "tüm değişiklikleri tersine" _ kimlik değerlerini, tetikleyiciler neden olduğu yan etkileri "kayıp" olabilir, çünkü .... – HABO

0

T-SQL'de TL ... CATCH ile ilgili iki kafam var. Fakat dil potansiyel-yararlı bir katkı olsa

, Sunulursa olmasının onu kullanmak için her zaman bir neden değildir.

(sadece bir örnektir fark) sizin

DELETE FROM Table WHERE... 

örneğini alarak. Bir hata ile başa çıkmanın tek yolu, kodun şemadan ciddi şekilde koparılmasıdır. (örneğin, birisi PK'nin sonundaki Tablo ile bir yabancı anahtar oluşturursa).

Uygun testler yapıldığında, kod ile şema arasındaki bu tür bir uyumsuzluk asla üretime geçmemelidir. Bunu yapacağı varsayıldığında, IMHO'nun "kaba", sonuçlandırılmayacak hata mesajı, neyin ters gittiğine dair daha iyi bir göstergenin, istemciye geri dönmek için bir SELECT deyimine "kibar" bir sargıdan ibarettir. (Hangi try/smelch antipattern SeanLange bahseder) tutar.

daha karmaşık senaryolar için, ben YTL ... CATCH bir kullanım alanı görebilirsiniz. IMHO, giriş parametrelerinin dikkatli bir şekilde doğrulanmasının yerini tutmaz.

1
Bir C# geliştirici olarak burada benim bakış açısı vermek istiyorum

: (sadece bir komut dosyasından bir kaç tablolarına ekleme) Yukarıda verilen basit senaryoda

gibi bir try/catch eklemek için hiçbir neden yoktur işlem için herhangi bir yararı yoktur. Her iki örnek de tam olarak aynı sonucu üretecektir: Ya tüm tablolar eklenecek veya olmayacak. Veritabanının durumu tutarlı kalır.(İŞLEM asla denir COMMIT beri geri alma örtülü senaryonun sonunda SQL Server tarafından çağrılır.)

Ancak, entegre mümkün olmayan try/catch şeyler yapabilirsiniz zamanlar vardır

hata işleme. Örneğin, hatayı bir hata tablosuna kaydetme. Böyle bir dosyayı açmaya çalışırken olarak geliştirici kontrolü dışındaki şeyler varken benim C# tecrübelerime

, bir deneme/yakalama kullanan tek zamandır. Böyle bir durumda, .NET framework tarafından üretilen bir istisna yönetmenin tek yolu deneme/yakalama geçer.

Bir saklı yordam yapıyor ve elle verilerin durumuna kontrol etmek ve manuel ROLLBACK TRANSACTION diyoruz, bunu görebiliyordu istedi olsaydı. Ama yine de bir deneme/yakalama gerektirmez.

İlgili konular