23 Mart 2013 Cumartesi

MS SQL'de TCL İşlemleri

Merhaba Webkolog takipçileri!

Veri tabanlarında çalışırken, özellikle finansal işlemler, envanter güncellemeleri veya karmaşık iş süreçleri gibi senaryolarda, birden fazla veri tabanı işleminin bir bütün olarak ele alınması hayati önem taşır. Yani, ya tüm işlemler başarılı bir şekilde tamamlanmalı ya da herhangi bir hata durumunda hiçbiri gerçekleşmemiş sayılmalıdır. İşte bu bütünlüğü sağlamak için Transaction Control Language (TCL) ve Transaction (işlem) kavramları devreye girer. Bugün sizlerle, MS SQL'de bu güçlü araçları nasıl kullanacağımızı detaylıca inceleyeceğiz. Hazırsanız, veri bütünlüğünü garantilemeye başlayalım!

---

Transaction (İşlem) Nedir ve Neden Önemlidir?

Bir Transaction, veri tabanındaki bir veya daha fazla mantıksal olarak ilişkili DML (Data Manipulation Language) işleminin (INSERT, UPDATE, DELETE) atomik bir birim olarak ele alınmasıdır. Atomiklik (bölünemezlik) ilkesi gereği, bir transaction içindeki tüm işlemler ya tamamen başarılı olur ve kalıcı hale gelir (Commit edilir) ya da herhangi bir adımda hata oluşursa tüm işlemler geri alınır (Rollback edilir).

Transaction'lar, veri tabanlarının ACID özelliklerini (Atomicity, Consistency, Isolation, Durability) sağlamasının temelidir. Bu özellikler, veri bütünlüğünü ve güvenilirliğini garanti eder:

  • Atomicity (Bölünmezlik): Bir transaction'daki tüm işlemler ya birlikte gerçekleşir ya da hiçbiri gerçekleşmez. Yarım kalmış bir işlem olmaz.
  • Consistency (Tutarlılık): Bir transaction, veri tabanını her zaman tutarlı bir durumdan diğer tutarlı bir duruma geçirir.
  • Isolation (İzolasyon): Eşzamanlı çalışan transaction'lar birbirini etkilemez. Her transaction, veri tabanının izole bir kopyası üzerinde çalışıyormuş gibi görünür.
  • Durability (Kalıcılık): Başarıyla tamamlanan (commit edilen) bir transaction'ın etkileri kalıcıdır ve sistem çökse bile kaybolmaz.
---

TCL İfadeleri: Transaction'ları Yönetmek

MS SQL'de transaction'ları yönetmek için dört temel TCL (Transaction Control Language) ifadesi kullanılır:

1. BEGIN TRANSACTION: İşlemi Başlatma

Yeni bir transaction başlatmak için kullanılır. Bu noktadan itibaren yapılan tüm DML (INSERT, UPDATE, DELETE) işlemleri, COMMIT edilene veya ROLLBACK edilene kadar geçici olarak tutulur.

BEGIN TRANSACTION;
-- veya
BEGIN TRAN; -- Daha kısa kullanım

-- Opsiyonel olarak transaction'a bir isim verilebilir
BEGIN TRANSACTION ParaTransferi;
2. COMMIT TRANSACTION: İşlemi Onaylama (Kalıcı Hale Getirme)

BEGIN TRANSACTION ile başlatılan tüm DML işlemlerini kalıcı hale getirir. Bu komut çalıştırıldığında, transaction içindeki tüm değişiklikler veri tabanına yazılır ve geri alınamaz hale gelir.

COMMIT TRANSACTION;
-- veya
COMMIT TRAN;

-- İsim verilen transaction'ı onaylama
COMMIT TRANSACTION ParaTransferi;
3. ROLLBACK TRANSACTION: İşlemi Geri Alma

BEGIN TRANSACTION ile başlatılan transaction içindeki tüm DML işlemlerini geri alır. Yani, transaction başladığından beri yapılan tüm değişiklikler iptal edilir ve veri tabanı transaction başlamadan önceki durumuna döner.

ROLLBACK TRANSACTION;
-- veya
ROLLBACK TRAN;

-- İsim verilen transaction'ı geri alma
ROLLBACK TRANSACTION ParaTransferi;
4. SAVE TRANSACTION: Kayıt Noktası Oluşturma

Bir transaction içinde belirli bir noktaya "kayıt noktası" (savepoint) oluşturmak için kullanılır. Bu, transaction'ın tamamını geri almak yerine, sadece belirli bir kayıt noktasına kadar geri dönmeye olanak tanır. Özellikle karmaşık ve uzun transaction'larda faydalıdır.

SAVE TRANSACTION KayitNoktasi1;

-- Kayıt noktasına geri dönme
ROLLBACK TRANSACTION KayitNoktasi1;
---

Pratik Bir Örnek: Para Transferi

Transaction'ların önemini en iyi gösteren örneklerden biri para transferidir. Bir hesaptan para çekilirken, aynı anda diğer hesaba para yatırılmalıdır. Eğer para çekme işlemi başarılı olur, ancak yatırma işlemi başarısız olursa, her iki işlemin de geri alınması gerekir ki para havada kalmasın ve veri tutarlılığı bozulmasın.

-- Örnek tablo yapısı (test için)
-- CREATE TABLE Accounts (AccountID CHAR(10) PRIMARY KEY, Balance MONEY);
-- INSERT INTO Accounts VALUES ('A1', 1000), ('A2', 500);

CREATE PROCEDURE sp_MoneyTransfer
    @GonderenHesapID CHAR(10),
    @AliciHesapID CHAR(10),
    @Miktar MONEY,
    @DurumKodu INT OUT
AS
BEGIN
    DECLARE @GonderenBakiye MONEY;
    SELECT @GonderenBakiye = Balance FROM Accounts WHERE AccountID = @GonderenHesapID;

    -- Yeterli bakiye kontrolü
    IF @GonderenBakiye >= @Miktar
    BEGIN
        BEGIN TRANSACTION; -- ** Transaction Başlat **
        BEGIN TRY
            -- Gönderen hesaptan para düşme
            UPDATE Accounts
            SET Balance = Balance - @Miktar
            WHERE AccountID = @GonderenHesapID;

            -- Hata kontrolü (örneğin güncellenen satır yoksa)
            IF @@ROWCOUNT = 0
            BEGIN
                RAISERROR('Gönderen hesap bulunamadı veya güncellenemedi.', 16, 1);
            END;

            -- Alıcı hesaba para ekleme
            UPDATE Accounts
            SET Balance = Balance + @Miktar
            WHERE AccountID = @AliciHesapID;

            -- Hata kontrolü
            IF @@ROWCOUNT = 0
            BEGIN
                RAISERROR('Alıcı hesap bulunamadı veya güncellenemedi.', 16, 1);
            END;

            COMMIT TRANSACTION; -- ** Tüm işlemler başarılı, kalıcı hale getir **
            SET @DurumKodu = 0; -- Başarılı
        END TRY
        BEGIN CATCH
            -- Herhangi bir hata oluşursa tüm işlemleri geri al
            ROLLBACK TRANSACTION; -- ** Hata oluştu, geri al **
            SET @DurumKodu = -1; -- Hata oluştu
            PRINT ERROR_MESSAGE(); -- Hatayı göster
        END CATCH;
    END
    ELSE
    BEGIN
        SET @DurumKodu = -2; -- Yetersiz bakiye
        PRINT 'Yetersiz bakiye.';
    END;
END;

-- Stored Procedure'ü çalıştırma örnekleri
DECLARE @Sonuc INT;

-- Başarılı transfer
EXEC sp_MoneyTransfer 'A1', 'A2', 200, @Sonuc OUT;
SELECT 'Transfer Durumu (Başarılı): ' + CAST(@Sonuc AS NVARCHAR); -- 0 dönmeli
SELECT * FROM Accounts; -- Bakiyeleri kontrol edin

-- Yetersiz bakiye durumu
EXEC sp_MoneyTransfer 'A1', 'A2', 2000, @Sonuc OUT;
SELECT 'Transfer Durumu (Yetersiz Bakiye): ' + CAST(@Sonuc AS NVARCHAR); -- -2 dönmeli

-- Tabloları temizle (test sonrası)
-- DROP TABLE Accounts;

Yukarıdaki örnekte, BEGIN TRANSACTION ile başlayan ve COMMIT TRANSACTION ile biten bir işlem bloğu görüyorsunuz. Eğer bu blok içinde herhangi bir UPDATE işlemi başarısız olursa (örneğin @@ROWCOUNT kontrolü veya RAISERROR ile), CATCH bloğu tetiklenir ve ROLLBACK TRANSACTION komutu ile tüm işlemler geri alınır. Bu, para transferi gibi kritik işlemlerde veri tutarlılığını garanti altına almanın en güvenli yoludur.

---

Önemli Notlar:

  • Bir transaction içinde genellikle sadece DML (INSERT, UPDATE, DELETE) işlemleri bulunur. DDL (CREATE, ALTER, DROP) işlemleri çoğu zaman implicit (örtülü) transaction'lar yaratır ve bunların geri alınması daha karmaşık olabilir.
  • Transaction'lara isim vermek (örneğin BEGIN TRANSACTION ParaTransferi;) özellikle iç içe transaction'larda veya debug yaparken faydalı olabilir. ROLLBACK TRANSACTION ParaTransferi; ile belirli bir isme sahip transaction'ı geri alabilirsiniz.
  • @@ERROR yerine TRY...CATCH bloklarını kullanmak, modern T-SQL'de hata yönetiminde daha esnek ve güvenilir bir yaklaşımdır. Ben de yukarıdaki örnekte bu yaklaşımı kullandım.
  • Uzun süren veya açık bırakılan transaction'lar, veri tabanında kilitlenmelere (locking) yol açarak performansı düşürebilir. Bu yüzden transaction'ları mümkün olduğunca kısa ve etkin tutmak önemlidir.

MS SQL'de transaction'lar ve TCL komutları, veri tabanı uygulamalarınızın güvenilirliğini ve veri bütünlüğünü sağlamak için temel yapı taşlarıdır. Özellikle kritik iş süreçlerinde, bu yapıları doğru ve bilinçli bir şekilde kullanmak, olası veri kayıplarını ve tutarsızlıkları önleyecektir. Her zaman 'ya hep ya hiç' felsefesini aklınızda bulundurarak kod yazın!

Webkolog'u takipte kalın!

Hepinize bol kodlu ve başarılı projeler dilerim!

0 yorum:

Yorum Gönder