SQL 2005 depolanmış procs hata işleme eklemek için en iyi yöntem nedir?


11

Depolanmış proc'ları çok iyi ölçekleyebilecekleri ve hata işleme içerebilecek kadar sağlam hale getirmenin iyi bir yolu nedir?

Ayrıca, depolanan bir proc'ta birden çok hata senaryosunu ele almanın ve çağıran uygulamalara anlamlı hata bilgileri döndürecek akıllı bir geri bildirim sistemine sahip olmanın en iyi yolu nedir?


2
SQL Server 2005'te daha yeni TRY CATCH bloğunu kullanmayı deneyin. Sommarskog.se/error_handling_2005.html
Sankar Reddy

Merhaba @Kacalapy ~ Gelecekte her soruyu kendi başına sormasını tavsiye etmek istiyorum ve bu şekilde her seferinde bir soruya odaklanmış belirli cevaplar alabiliriz. Bunu bu soru ile yapmanızı tavsiye ediyorum.
jcolebrand

Yanıtlar:


12

Alex Kuznetsov, Savunma Veritabanı Programlama (Bölüm 8) kitabında T-SQL TRY ... CATCH, T-SQL işlemleri ve SET XACT_ABORT ayarlarını kapsayan ve istemci tarafı hata işleme özelliğini içeren harika bir bölüm içeriyor. Hangi seçeneklerden hangisini gerçekleştirmeniz gerektiğine en uygun olana karar vermede size çok yardımcı olacaktır.

Bu kullanılabilir ücretsiz olarak bu sitede . Hiçbir şekilde şirkete bağlı değilim, ancak bu kitabın basılı kopyasına sahibim.

Bu konuda Alex tarafından çok iyi açıklanmış çok az detay var.

Nick'in isteği üzerine ... (ancak bunların hepsi bölümde değil)

Ölçekleme açısından, hangi faaliyetlerin db kodunda olması ve hangisinin uygulamada olması gerektiği konusunda acımasızca dürüst olmanız gerekir. Hiç hızlı yürütme kodu yöntem başına tek bir endişe için tasarım geri gelme eğilimi fark ettiniz mi?

İletişim kurmanın en kolay yolu özel hata kodlarıdır (> 50.000). Aynı zamanda oldukça hızlı. Bu, db kodunu ve uygulama kodunu senkronize tutmanız gerektiği anlamına gelir. Özel bir hata koduyla, hata mesajı dizesine yararlı bilgiler de döndürebilirsiniz. Kesinlikle bu durum için bir hata kodunuz olduğundan, uygulama koduna hatanın veri biçimine göre uyarlanmış bir ayrıştırıcı yazabilirsiniz.

Ayrıca, hangi hata durumlarının veritabanında yeniden deneme mantığına ihtiyacı vardır? X saniye sonra tekrar denemek isterseniz, uygulama kodunda bunu işlemek daha iyi olur, böylece işlem o kadar da engellemez. Bir DML işlemini yalnızca hemen yeniden gönderiyorsanız, SP'de tekrar etmek daha verimli olabilir. Yine de, yeniden denemeyi gerçekleştirmek için kodu çoğaltmanız veya bir SP katmanı eklemeniz gerekeceğini unutmayın.

Gerçekten, bu şu anda SQL Server'da şu anda TRY ... CATCH mantığıyla en büyük acı. Bu yapılabilir, ama biraz bir yulaf. SQL Server 2012'de bu duruma gelen bazı geliştirmelere, özellikle de sistem istisnalarını yeniden atmaya bakın (orijinal hata numarasını koruyarak). Ayrıca, özellikle günlük kaydı amacıyla hata iletileri oluşturmada bazı esneklik kazandıran FORMATMESSAGE vardır .


Büyük tavsiye ve çok iyi bir kitap!
Marian

Red Gate, son derece yararlı birkaç ücretsiz E-kitap sunuyor ve bu kesinlikle daha iyi olanlardan biri. Büyük öneri.
Matt M

Kitaplarının hepsi bunu yapmıyor, ancak Kuznetsov'un "Savunma ..." kitabının ücretsiz sürümü, eşzamanlılıktan kurtulabilen İşlem İzolasyon Seviyeleri ve Geliştirme Değişiklikleri hakkındaki son 2 bölümü içermiyor. Benim için. oradaki içerik satın almaya değerdi.
Phil Helmer

7

Bu bizim şablonumuz (hata günlüğü kaldırıldı)

Notlar:

  • XACT_ABORT olmadan, tüm TXN başlangıç ​​ve kesinleştirme / geri almaların eşleştirilmesi gerekir
  • TRANCOUNT tutarındaki taahhüt azalışı
  • Bir geri alma @@ TRANCOUNT değerini sıfıra döndürür, böylece 266 hatası alırsınız
  • Yalnızca geçerli katmanı GERİ ÇEKMEZ (örneğin geri almada @@ TRANCOUNT azaltma)
  • XACT_ABORT 266 hatasını bastırıyor
  • Depolanan her proc aynı şablona uymalıdır, böylece her çağrı atomiktir
  • XACT_ABORT nedeniyle geri alma kontrolü aslında gereksizdir. Ancak, beni daha iyi hissettiriyor, onsuz tuhaf görünüyor ve istemediğiniz durumlara izin veriyor
  • Bu, istemci tarafı TXN'lere izin verir (LINQ gibi)
  • Remus Rusanu bir sahiptir benzer kabuk kullandığı puan kaydetmek söyledi. Atomik bir DB çağrısını tercih ediyorum ve makaleleri gibi kısmi güncellemeler kullanmıyorum

... bu yüzden ihtiyacınız olandan daha fazla TXN oluşturmayın

Ancak,

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

@@ TRANCOUNT 0'dan büyükse ne olur? herhangi bir iş yapmıyorsunuz veya geri bildiriminiz mi var?
kacalapy

@kacalapy: yuvalanmış bir işlem diye bir şey yoktur, bu yüzden başka bir scribd.com/doc/49579859/33/Nested-Transactions-Are-Real
gbn 28:11

3

Try / Catch kullanıyorum, ancak mümkün olduğunca çok bilgi topluyorum ve geri alma SONRASI bir hata günlüğüne yazıyorum. Bu örnekte, "LogEvent", olayların ayrıntılarını içeren bir EventLog tablosuna yazan depolanmış bir yordamdır. GetErrorInfo (), tam hata mesajını döndüren bir işlev çağrısıdır.

Bir hata oluştuğunda, bilgi toplanır, yordam hata işleme bölümüne atlar ve bir geri alma gerçekleştirir. Bilgiler günlüğe yazılır, ardından yordam çıkar.

Ekstra prosedür / fonksiyon çağrıları göz önüne alındığında, biraz üstte görünüyor. Ancak bu yöntem, hata ayıklamaya çalışırken çok faydalıdır.

exec LogEvent @Process, @Database, 'Blah blah blah eklemeye çalışıyor'
BAŞLAYIN
  MyTable'a ekle
  Değerleri seçin
    MyOtherTable tarafından

  @rowcount = @@ ROWCOUNT seçin
BİTİR TL
-- Hata yönetimi
YAKALAMAYI BAŞLAT
  @error = ERROR_NUMBER () seçin,
         @rowcount = -1,
         @TableAction = 'ekle',
         @TableName = @Database + '.MyTable',
         @AdditionalInfo = '(Blah blah blah eklemeye çalışıyor)' + dbo.GetErrorInfo ()
   GOTO TableAccessError
END CATCH

.
.
.
.

TableAccessError:
EĞER (@@ TRANCOUNT> 0) GERİ DÖN
@output = üst seçimi (@TableAction) + 
       'HATA -' + sırasında bir hata oluştu 
       case (@TableAction)
         'güncelleme' olduğunda 'güncelleme'
         'sil' ve ardından 'silme'
         başka @TableAction + 'ing'
       bitiş + 
       'kayıtlar' + 
       örnek (@TableAction) 
         'seçin' sonra 'seçin' 
         'güncelleme' sonra 'giriş' 
         'ekle' sonra 'içine'
         başka 'dan'   
         bitiş + 
         '' @TableName + 'tablosu.'
@output = @output + '@@ HATA seçin:' + dönüştür (varchar (8), @ hata) 
@output = @output + '@@ ROWCOUNT:' + dönüştür (varchar (8), @ rowcount) seçin 

@output = @output + isnull öğesini seçin (@AdditionalInfo, '')
exec LogEvent @Process, @Database, @Output
Günlüklü RAISERROR (@ çıktı, 16,1)
@ReturnCode = -1 seçin
GOTO THE_EXIT


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.