BEGIN TRY etiketine sahip kayıtlar gösteriliyor.
BEGIN TRY etiketine sahip kayıtlar gösteriliyor.

SQL'de TRY CATCH Kullanımı

Bu makalemde SQL Server Hata Yakalama Bloğu (TRY-CATCH) kullanımına değineceğim. 

TRY CATCH Yapısı
TRY CATCH yapısı TRY ve CATCH bloğundan oluşur. Eğer TRY bloğunda bir hata oluşursa kontrol CATCH bloğuna geçer. Bir hata oluşmamışsa CATCH blogu devreye girmez. Bir hata varsa CATCH blogunda hata yakalanır.  CATCH blogunun işletilmesi tamamlandıktan sonra akış bloktan sonraki kodlarla devam eder.

TRY CATCH kullanımında sadece TRY bloğunu tanımlayıp bırakamayız. Bir TRY bloğu tanımladıysak CATCH bloğunuda tanımlamak zorundayız.

Genel Yapısı:
BEGIN TRY
--SQL Kodlar (Hata olabilecek kod bloğu)
END TRY
BEGIN CATCH
--SQL Kodlar (Hata olduğunda hatanın yakalandığı kısım.)
END CATCH

MS SQL'de TRY CATCH fonksiyonunun çeşitli işlevsel özellikleri vardır. Bu özellikler CATCH bloğu içinde kendi değerlerini korurlar, CATCH bloğu dışında ise geriye NULL dönerler. 

ERROR_SEVERITY() Hata Dereceleri
  • 0 veya 10 : Kullanıcı veri girişinden kaynaklanan hata 
  • 11-16 arası: Kullanıcının düzeltebileceği bir hata 
  • 17 : Yetersiz kaynak hatası (Diskin dolu olması veya tablonun salt okunur olması vb.) 
  • 18 : Yazılımdan kaynaklanan hata 
  • 19 : Constraint'lere takılan bir hata 
  • 20-25 arası: Kritik hatalar
Örnek 1:
BEGIN TRY
DECLARE @Sayi int = 8/0
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER()    AS 'Hata Numarası',
ERROR_SEVERITY()  AS 'Hata Derecesi',
ERROR_STATE()     AS 'Hata Kod Değeri',
ERROR_PROCEDURE() AS 'Hata SP',
ERROR_LINE()      AS 'Hata Satır Numarası',
ERROR_MESSAGE()   AS 'Hata Mesajı'
END CATCH

 
Örneğimizde 8 sayısı 0'a bölünmeye çalışılıyor. 0'a bölme hatası alıyoruz ve CATCH bloğuna geçiyoruz. Fakat sorgu devam ediyor. Eğer TRY-CATCH kullanmasaydık sorgumuz hata verdiği anda sonlanacaktı.

NOT: TRY-CATCH sadece çalışma anındaki hataları yakalayabilir. SQL kodumuzdaki syntax hatalarını yakalayamaz.

Örnek 2:
BEGIN TRY
DROP TABLE TABLO5;
END TRY
BEGIN CATCH
PRINT 'Hata Oluştu'
PRINT ERROR_NUMBER();
PRINT ERROR_SEVERITY();
PRINT ERROR_STATE();
PRINT ERROR_LINE();
PRINT ERROR_MESSAGE();
END CATCH

Örneğimizde mevcut olmayan bir tabloyu drop etmek istedim ve dolayısıyla varolmadığı için bir hata oluştu. CATCH bloğuna PRINT ile "Hata Oluştu" mesajını ve TRY-CATCH fonksiyon özelliklerinide yine PRINT ile ekrana yazdırdık.

SQL'de Transaction Oluşturma ve Kullanımı

Transaction  Nedir?
Transaction için SQL Server ortamında kullandığımız iş birimidir diyebiliriz. Çoğu zaman bir transaction yalnızca bir türde işlem yapar, yani sadece veri silme, veri güncelleme veya veri ekleme gibi tek türde işlem yapar. Ama bir transaction içinde birden fazla da işlem yapılabilir. Yine transaction içinde SELECT işlemleri de yapılabilmektedir. Transaction, çalışma yapısı olarak ya bütün işlemleri gerçekleştirir ya da hiçbirini gerçekleştirmez. İşlemlerden biri başarısız olursa, hiçbir işlem gerçekleşmez; ancak tüm işlemler başarılı olduğunda  Transaction, içinde gerçekleşen tüm veri değişikliklerini onaylamış demektir.  

Transaction bloğundaki işlemlerin hepsi başarılı olduğunda Transaction Commit (Onaylama) komutu çalışır ve değişiklikler veritabanında gerçekleşmiş olur. ancak bir hata varsa işleyiş bozulur ve Transaction Rollback (Geridönüş) komutu çalışır, bu şekilde tüm işlemler geri alınır ve en başa dönülür. Böylece veri kaybına karşı bir çeşit koruma mekanizması oluşturulmuş olunur.

Transaction  Nerde ve Ne Zaman Kullanırız
Örneğin veri tabanımızdan silinen kayıtları, başka bir veri tabanına yedekliyorsak. Bir silinme ve bir kaydetme işlemi söz konusu. Bu işlemlerin sırayla gerçekleşmesi gerekiyor. Silinme işlemi başarılı bir şekilde tamamlandı. Fakat kaydetme işleminde bir hata meydana geldi. Bu hata yetersiz hafızadan kaynaklanabilir, sistem işlem sırasında yeniden başlatılmıştır veya fiziksel bir arıza nedeniyle kapanmıştır. Bu nedenler yüzünden silinmiş kaydımıza elveda demek yerine, böylesi sorunlarla karşılaşma ihtimalimize karşı önlemimizi almamız gerekir. Çalışmasını istediğimiz kod bloğunu "transaction" bloklarına alırız ve sorun çözülmüş olur.

Şimdi örnekle konuyu pekiştirelim.

Örnek: Bir banka sisteminde para havale etme işlemi için örnek bir transaction tasarlayalım. Öncelikle aşağıdaki gibi bir "HESAP" tablosu oluşturalım ve tablomuzda müşterilere ait HESAP_ID, AD, SOYAD, HESAP_NO, BAKIYE bilgilerini tutalım. 
CREATE DATABASE BANKA
USE BANKA

CREATE TABLE HESAP
(
HESAP_ID INT PRIMARY KEY IDENTITY (1,1) NOT NULL,
AD       VARCHAR(30) NOT NULL,
SOYAD    VARCHAR(30) NOT NULL,
HESAP_NO INT         NOT NULL,
BAKIYE   INT         NOT NULL
)

Oluşturmuş olduğumuz "HESAP" tablomuza örnek kayıtlar girelim.
INSERT INTO HESAP VALUES('İBRAHİM','BAYRAKTAR',19265,7000)
INSERT INTO HESAP VALUES('SAMET','ULUTURK',19572,10000)
INSERT INTO HESAP VALUES('RAMAZAN','PINARBAŞI',19752,9500)
INSERT INTO HESAP VALUES('RAŞİT','BAKIR',19912,17000)

"Samet ULUTURK'ün hesabından, İbrahim BAYRAKTAR'ın hesabına 1000 TL havale yapılsın." Bu işlem için izleyeceğimiz algoritma Samet ULUTURK'ün bakiye bilgisini 1000 azaltmak ve İbrahim BAYRAKTAR'ın bakiye bilgisini 1000 artırmak olacaktır.
UPDATE HESAP SET BAKIYE = BAKIYE - 1000 --1.Sorgu
WHERE AD='SAMET' AND SOYAD='ULUTURK'

UPDATE HESAP SET BAKIYE = BAKIYE + 1000 --2.Sorgu
WHERE AD='İBRAHİM' AND SOYAD='BAYRAKTAR'
Havale işleminin gerçekleşmesi için bu iki sorgunun aynı anda gerçekleşmesi gerekir ve sistem kullanıcısı bu iki sorguyu birden çalıştırıyor. Şimdide örnek işlemimizde oluşabilecek olası hata senaryolarını inceleyelim.

Hata Olasılığı 1: Birinci SQL sorgumuzun çalışması fakat ikinci SQL sorgumuzda hata oluşması. Bu durumda Samet ULUTURK'ün hesabından 1000 TL eksilme olacak fakat İbrahim BAYRAKTAR'ın hesabında herhangi bir değişiklik olmayacaktır.

Hata Olasılığı 2: Birinci SQL sorgumuzda hata oluştu ve ikinci SQL sorgumuzun çalışması durumunda Samet ULUTURK'ün hesabından herhangi bir eksilme olmayacak fakat İbrahim BAYRAKTAR'ın hesabına 1000 TL eklenecek.

Örneğimizdeki gibi problemlerin ve olası hatalardan oluşacak karmaşanın önüne geçmek için  "transaction" yapısını kullanmalıyız. "transaction" sayesinde her iki sorguda birden çalıştıralacak, iki sorguda başarılı ise "transaction" onaylanacak fakat herhangi bir hata durumunda he iki sorguda iptal edilecek.

"transaction" yapısını SQL kodlarında kullanırken COMMIT ve ROLLBACK komutları kullanılır.

COMMIT komutu ile çalıştırılan tüm SQL komutlarının başarılı olması halinde işlemler veri tabanına yansıtılır. ROLLBACK komutu ise herhangi bir hata oluşumunda tüm işlemleri geri alır. 

Transaction  Oluşturalım
BEGIN TRANSACTION
BEGIN TRY

UPDATE HESAP SET BAKIYE = BAKIYE - 1000
WHERE AD='SAMET' AND SOYAD='ULUTURK'

UPDATE HESAP SET BAKIYE = BAKIYE + 1000
WHERE AD='İBRAHİM' AND SOYAD='BAYRAKTAR'

COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH

"BEGIN TRANSACTION" ile "transaction" işlemini başlatıyoruz. Tek bir komut gibi çalışmasını istediğimiz SQL kodlarımızı yazdıktan sonra  "transaction" işlemini "COMMIT" ile sonlandırıyoruz. "COMMIT"  komutuna gelene kadar işlemde hata olsa da olmasa da, işlem sonuçları tablomuza yansımayacaktır. "END TRY" ile blogumuzu kapatıyoruz. İşlemde bir hata ile karşılaşılması durumunda "BEGIN CATCH" blogu devreye girecek ve "ROLLBACK" komutu ile yapılan işlemler geri alınacak.