Error Handling
22 Ocak 2017 Pazar
Sql Server, hata mesajlarını kullanır ve bu hata mesajlarını'da veritabanında saklayarak kontrol edilmesini sağlar. Sql Server'da tanımlı olan hata mesajlarına sys.messages sistem tablosundan ulaşılabilir.Sql Server 2000 sürümüyle tanıştığımız @@Error, Sql Server 2005 ve sonrasında'da kullanılan Try..Catch hata yönetimleri, C# ya da Java'daki programlama mantığıyla birebir aynıdır.
Raiserror Kullanımı :
Uygulamalarımızda meydana gelen hataları devreye almak için kullanılan bir fonksiyondur.
Yazım şekli aşağıdaki gibidir:
RAISERROR('Hata Mesajı', HataSeviyesi, HataDurumu)
HataSeviyesi=Mesajın kritiklik düzeyini ifade eder. 0-25 arası bir değer alabilir. 0-10 aralığı kullanıcının girdiği verilerden kaynaklı hataları, 11-16 aralığı kullanıcının düzeltebileceği türden hataları, tek başına 17 rakamı yetersiz kaynak, disk dolu, tablo okumaya korumalı gibi hatayı, 18 rakamı ölümcül olmayan dahili hatayı, 19 rakamı Sql Server'ın kısıtlarına takılma sonucu oluşan hatayı(bu hatada WITH LOG özelliğinin kullanılması gerekir), 20-25 aralığı ölümcül(sadece admin'in ekleyebildiği) hataları ifade eder.Buraya genellikle 16 rakamı geçilir..
HataDurumu= 1 - 255 arası değer alabilir ancak raiserror'un hata üretebilmesi için gereken değer 1-127 aralığıdır.
@@ERROR Kullanımı :
@@Error sistem fonksiyonunun varsayılan geri dönüş değeri 0(sıfır) olmayan bir değerdir. Şayet sql ifadesinde bir hata var ise geriye 0(sıfır)'dan farklı bir değer döner.
@@Error ifadesi her sql cümlesinden sonra baştan başlatılarak(reset) 0 değerini alır(yani hata içermeyen bir geri dönüş de diyebiliriz buna). Dolayısıyla hata yakalamak istediğiniz sql cümlelerinden hemen sonra @@Error fonksiyonunu kullanıyor olmanız gerekir.
Örnek üzerinden gidecek olursak; farzedelimki UrunID'si 2 olan bir değerim halihazırda olsun ancak ben yine de 2 no'lu bir değeri eklemek isteyeyim.Böyle bir durumda içerde mükerrer kayıt oluşmaması için SQL Server bunu engelleyecektir ve de insert cümleciğinin hemen peşine yazılan @@Error fonksiyonu'da bu hatayı yakalayacaktır.. Aşağıda birbirinin benzeri 2 kod örneği mevcut, sadece Örnek2'de araya çalışan bir sql cümlesi ekledim.Böylece hatayı yakalamadan yola devam edileceğini sizlere göstermek istiyorum.
Örnek1:
insert into tblUrun(UrunID, UrunAd) values(2, 'Telefon')
if(@@ERROR<>0) --Hata var ise yakala
Print
'Hata oluştu!' --2 No'lu kayıt veritabanında olduğu için bu blok çalışır.
Else
Print
'Hata yok.'
Örnek2:
insert into tblUrun(UrunID, UrunAd) values(2, 'Telefon')
select* from tblUrun
if(@@ERROR<>0)
Print
'Hata oluştu!'
Else
Print
'Hata yok.'
Örnek1 çalıştırıldığında 'Hata oluştu' bloğuna düşecektir ancak Örnek2'de araya çalışan bir sql cümlesi eklendiği için 'Hata yok' bloğuna düşecektir. Çünkü @@Error fonksiyonu çalışan her sql cümleciğinden sonra sıfır(0) değerine sahip olur.
Örnek1 ve Örnek2'de anlatmak istediğim @@Error sistem fonksiyonunun 0(sıfır) değerini yakalayıp yakalayamadığıdır. Şayet Örnek2 demosunda olduğu gibi aralara çalışan bir sql ifadesi yazmanız gerekiyor ise o zaman aşağıdaki örnek kod bloğu işinizi çözecektir. Aşağıdaki uygulamada, değişken atama yoluyla @@Error fonksiyonu kullanılmıştır.
declare @Error int
insert into tblUrun(UrunID, UrunAd) values(2, 'Telefon')
set @Error =@@ERROR
select* from tblProduct
if(@Error<>0)
Print 'Error Occured'
Else
Print 'No Errors'
@@Error fonksiyonu, hata oluşumunun hemen ardından kullanıldığında anlamlıdır.Araya herhangi bir çalışan satır girdiğinde, @@Error değeri sıfırlanacak ve hatayı yakalama şansımızda ortadan kalkacaktır.Dolayısıyla böyle bir durum için hata olma ihtimali olan her ifadeden sonra @@Error fonksiyonunu kullanmanız gerekir.Böyle bir işleme girişmekte pek mantıklı değildir elbette..
Sql Server 2005 ile birlikte hayatımıza giren TRY..CATCH yapısı bize böylesi sıkıntılı durumların üstesinden rahatça gelme şansı veriyor.
Try..Catch Kullanımı
Try..Catch için, @@Error fonksiyonunun rahat ve verimli bir alternatifidir diyebiliriz. Ayrıca iç içe kullanabilirsiniz.
Yazım şekli(sentaks) aşağıdaki gibidir:
BEGIN TRY
T-Sql kodları
END TRY
BEGIN CATCH
T-Sql kodları
END CATCH
Önemli Not: TRY bloğu tanımlı ise CATCH bloğuda tanımlı olmak zorundadır.Tek başına TRY bloğu tanımlanamaz.
Yukarıda raiserror başlığı altında hataseviyesi rakamlarının karşılığını incelemiştik bu bağlamda şayet BEGIN-TRY bloğu içersinde hata seviyesi 10'dan büyük bir hata durumu olur ise sql akışı otomatik olarak BEGIN-CATCH bloğuna düşer.
Şimdi bu söylemimizi bir örnekle pekiştirelim. Aşağıdaki örnekte hataseviyesi 10'dan büyük bir rakam girişi yapılmıştır. Sizde kendi veritabanınızda örneği bire-bir deneyip test edebilirsiniz.
-----------------------------------------------------------
BEGIN TRY
PRINT 'try bloğu başladı'
RAISERROR('beklenmedik bir durum oluştu', 11, 1)
PRINT 'try bloğu hala devam ediyor'
END TRY
BEGIN CATCH
PRINT 'catch bloğu devreye girdi'
PRINT CAST(ERROR_NUMBER() AS VARCHAR(6))+' numaralı bir hata oluştu ve yakalandı'
END CATCH
-----------------------------------------------------------
Sorgu Sonucu: try bloğu başladı
catch bloğu devreye girdi
50000 numaralı bir hata oluştu ve yakalandı
Bu örnek'te 11 yerine daha aşağı seviye bir numara verseydik CATCH bloğu asla devreye girmeyecekti.(sizde deneyiniz lütfen) Çünkü 11'den aşağı seviye hatalar önemsiz olduğu için CATCH bloğuna düşmezler. Ek olarak; 21 ve yukarısı seviye olduğunda TRY/CATCH bu hatayı asla yakalamayacaktır.Çünkü bu hata bağlantıyı sona erdirecek seviyede ağır olan bir sistem hatasına tekabül eder.
Son örneğimizde oluşan hatayı CATCH bloğu içersindeki ERROR_NUMBER() fonksiyonu ile okuduğumuz dikkatinizi çekmiştir. Bu fonksiyon @@Error'a göre çok daha kullanışlı'dır.Bu türe benzer fonksiyonlara bir göz atalım dilerseniz:
ERROR_NUMBER(): sys.messages tablosu referans alınarak, fırlatılan hata'nın kodunu belirtir.
ERROR_MESSAGE(): Hata mesaj metni'dir.
ERROR_SEVERITY(): Hata'nın dışa dönük kritiklik durumudur.
ERROR_STATE(): Hata'nın sisteme dönük kritiklik seviyesi.
ERROR_PROCEDURE(): Hataya neden olan prosedür.
ERROR_LINE(): Hataya neden olan satır.
Yukarıdaki fonksiyonların tümü hatayı geri almak için kullanılır.
Önemli Not: Try..Catch, UDF fonksiyonlarda kullanılamaz!
Takip eden makalelerimde görüşmek üzere, hepinize iyi çalışmalar dilerim.