İçeriğe geç
academia.sh

Ders 08 / 20

İşlem Denetimi

Otomatik kesinleştirme kipi, BEGIN ile açık işlem başlatma, COMMIT ve ROLLBACK, deyim hatasının işlemi kendiliğinden bitirmemesi ve bağlantı koptuğunda örtük geri alma.

İçindekiler

Önceki konu boyunca yazılan her sorgu tek bir deyimdi ve tek bir soruya yanıt verdi. Veri değiştiren işler ise çoğu zaman tek deyime sığmaz. Bir kitabın ödünç verilmesi iki değişiklik gerektirir: ödünç kaydının açılması ve kitabın raf durumunun güncellenmesi. İkisinden biri yapılıp diğeri yapılmazsa veritabanı, gerçekte var olmayan bir durumu anlatır — kayıt açık görünürken kitap rafta ya da tersi.

İlişkisel Kuram kursunda ACID özellikleri tanıtılırken atomiklik “ya hep ya hiç” olarak tanımlanmıştı. İşlem (transaction), bu tanımın uygulamadaki karşılığıdır: birden çok deyimi, motorun bölünmez saydığı tek bir birim hâline getirir.

Otomatik Kesinleştirme

Açık bir işlem başlatılmadan çalıştırılan her deyim, kendi başına bir işlemdir. Bu davranışa otomatik kesinleştirme (autocommit) denir: deyim başarıyla biterse etkisi kalıcıdır, hata verirse hiç olmamış gibidir.

rm -f k1.db
sqlite3 -box -header k1.db <<'SQL'
CREATE TABLE kitap(id INTEGER PRIMARY KEY, baslik TEXT, rafta INT NOT NULL DEFAULT 1);
INSERT INTO kitap VALUES (1,'Kayip Zaman',1),(2,'Sessiz Ev',1),(3,'Sayilar Kurami',1);
UPDATE kitap SET rafta = 0 WHERE id = 1;
SQL
sqlite3 -box -header k1.db 'SELECT id, baslik, rafta FROM kitap ORDER BY id;'
rm -f k1.db
┌────┬────────────────┬───────┐
│ id │     baslik     │ rafta │
├────┼────────────────┼───────┤
│ 1  │ Kayip Zaman    │ 0     │
│ 2  │ Sessiz Ev      │ 1     │
│ 3  │ Sayilar Kurami │ 1     │
└────┴────────────────┴───────┘

Birinci komut veritabanını kurup güncelledi ve sona erdi; ikinci komut ayrı bir süreç olarak açtı ve değişikliği gördü. Hiçbir yerde kesinleştirme yazılmadı, çünkü her deyim kendiliğinden kesinleşti.

Bu kip tekil değişiklikler için elverişlidir, birlikte olması gereken değişiklikler için tehlikelidir: iki deyim arasında bir hata olursa birincisi kalıcıdır. Otomatik kesinleştirmenin açık ya da kapalı olması ve nasıl kapatıldığı motora göre değişir; bazı motorlarda BEGIN yazmak, bazılarında bir ayar değiştirmek gerekir. Değişmeyen, açık işlemin COMMIT ya da ROLLBACK ile bitirilmesidir.

Başlatma, Kesinleştirme, Geri Alma

Açık işlem BEGIN ile başlar. O andan sonraki değişiklikler yalnız o işlem içinden görünür; COMMIT çalıştırılana kadar kalıcı değildir. ROLLBACK, işlem başladıktan sonra yapılmış tüm değişiklikleri siler:

rm -f k2.db
sqlite3 -box -header k2.db <<'SQL'
CREATE TABLE kitap(id INTEGER PRIMARY KEY, baslik TEXT, rafta INT NOT NULL DEFAULT 1);
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT, uye_id INT, alis TEXT, iade TEXT);
INSERT INTO kitap VALUES (1,'Kayip Zaman',1),(2,'Sessiz Ev',1),(3,'Sayilar Kurami',1);

BEGIN;
INSERT INTO odunc(kitap_id, uye_id, alis) VALUES (1, 4, '2024-03-11');
UPDATE kitap SET rafta = 0 WHERE id = 1;
SELECT 'islem icinde' AS an, (SELECT COUNT(*) FROM odunc) AS odunc_sayisi,
       (SELECT rafta FROM kitap WHERE id = 1) AS kitap1_rafta;
ROLLBACK;

SELECT 'geri alindiktan sonra' AS an, (SELECT COUNT(*) FROM odunc) AS odunc_sayisi,
       (SELECT rafta FROM kitap WHERE id = 1) AS kitap1_rafta;
SQL
rm -f k2.db
┌──────────────┬──────────────┬──────────────┐
│      an      │ odunc_sayisi │ kitap1_rafta │
├──────────────┼──────────────┼──────────────┤
│ islem icinde │ 1            │ 0            │
└──────────────┴──────────────┴──────────────┘
┌───────────────────────┬──────────────┬──────────────┐
│          an           │ odunc_sayisi │ kitap1_rafta │
├───────────────────────┼──────────────┼──────────────┤
│ geri alindiktan sonra │ 0            │ 1            │
└───────────────────────┴──────────────┴──────────────┘

İşlem içinde ödünç kaydı vardı ve kitap raftan düşmüştü. Geri alma sonrasında ikisi de eski hâline döndü — tek tek değil, birlikte. Atomiklik budur: geri alma kısmi bir sonuç bırakmaz.

İşlem içindeki SELECT deyimi, henüz kesinleşmemiş kendi değişikliklerini görüyor. Bu, işlemin kendi içinde tutarlı olmasının gereğidir; aynı anda başka bir bağlantının bu satırları görüp göremeyeceği ayrı bir sorudur ve yalıtım düzeyleri dersinde ele alınacaktır.

COMMIT yazılsaydı iki değişiklik de kalıcı olurdu. Kesinleştirmenin kalıcılık anlamı da tanımlıdır: COMMIT başarıyla döndüğünde değişiklikler, hemen ardından gelen bir güç kesintisinde bile kaybolmaz. Motorun bunu nasıl sağladığı — yazma öncesi günlük — İlişkisel Veritabanı Yönetimi kursunun konusudur.

Deyim Hatası İşlemi Bitirmez

Sık yapılan bir varsayım, işlem içindeki bir deyimin hata vermesi hâlinde işlemin kendiliğinden geri alınacağıdır. Standart davranış bu değildir: hata veren deyim etkisiz kalır, işlem açık kalmaya devam eder ve kararı uygulama verir.

Aşağıdaki şemada kısmi bir tekillik dizini var: bir kitabın aynı anda birden çok açık ödünç kaydı olamaz. İkinci kez ödünç verme denemesi bu kısıta takılır:

rm -f k3.db
sqlite3 -box -header k3.db <<'SQL'
CREATE TABLE kitap(id INTEGER PRIMARY KEY, baslik TEXT, rafta INT NOT NULL DEFAULT 1);
CREATE TABLE odunc(id INTEGER PRIMARY KEY, kitap_id INT, uye_id INT, alis TEXT, iade TEXT);
CREATE UNIQUE INDEX odunc_acik ON odunc(kitap_id) WHERE iade IS NULL;
INSERT INTO kitap VALUES (1,'Kayip Zaman',0),(2,'Sessiz Ev',1);
INSERT INTO odunc(kitap_id, uye_id, alis) VALUES (1, 4, '2024-03-11');

BEGIN;
INSERT INTO odunc(kitap_id, uye_id, alis) VALUES (1, 7, '2024-03-12');
UPDATE kitap SET rafta = 0 WHERE id = 1;
SELECT 'hata sonrasi islem icinde' AS an, COUNT(*) AS odunc_sayisi FROM odunc;
ROLLBACK;
SELECT 'geri alindiktan sonra' AS an, COUNT(*) AS odunc_sayisi FROM odunc;
SQL
rm -f k3.db
Runtime error near line 8: UNIQUE constraint failed: odunc.kitap_id (19)
┌───────────────────────────┬──────────────┐
│            an             │ odunc_sayisi │
├───────────────────────────┼──────────────┤
│ hata sonrasi islem icinde │ 1            │
└───────────────────────────┴──────────────┘
┌───────────────────────┬──────────────┐
│          an           │ odunc_sayisi │
├───────────────────────┼──────────────┤
│ geri alindiktan sonra │ 1            │
└───────────────────────┴──────────────┘

Üç şey birden görülüyor. Birincisi, hatalı INSERT etkisiz kaldı; ödünç sayısı 1’de kaldı. İkincisi, işlem kapanmadı: sonraki deyimler çalışmayı sürdürdü ve UPDATE uygulandı. Üçüncüsü, geri alma bu UPDATE etkisini de sildi.

İkinci nokta, gerçek bir hata kaynağıdır. Hata iletisi göz ardı edilip COMMIT yazılsaydı, ödünç kaydı açılmadığı hâlde kitap raftan düşmüş olarak kesinleşecekti — tam olarak kaçınılmak istenen tutarsızlık. Bu yüzden uygulama kodunda her deyimin sonucu denetlenir ve hata durumunda açıkça ROLLBACK çalıştırılır.

Hata iletisinin biçimi motora göre değişir; buradaki metin, kısıtın adını ve türünü veren tipik bir örnektir. Değişmeyen, ihlalin deyim düzeyinde raporlanması ve işlemin kaderinin uygulamaya bırakılmasıdır. Bazı motorlarda işlem, hatadan sonra yalnız geri alma kabul eden bir kilitli duruma geçer; bu ayrımın hedef motorda bilinmesi gerekir.

Bağlantı Koptuğunda

Kesinleştirilmemiş bir işlem, bağlantı sona erdiğinde geri alınır. Bu, uygulamanın açık bir şey yapmasını gerektirmez; motorun garantisidir. Aşağıdaki betik bir işlem başlatıp satır ekler ve COMMIT yazmadan süreci sonlandırır:

cat > kesintili.mjs <<'JS'
import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync('kesinti.db');
db.exec(`
  CREATE TABLE IF NOT EXISTS odunc(id INTEGER PRIMARY KEY, kitap_id INT,
                                   uye_id INT, alis TEXT);
`);
db.exec("BEGIN");
db.exec("INSERT INTO odunc(kitap_id, uye_id, alis) VALUES (1, 4, '2024-03-11')");
console.log('işlem içinde görülen satır:',
            db.prepare('SELECT COUNT(*) AS n FROM odunc').get().n);
process.exit(0);
JS
rm -f kesinti.db
node kesintili.mjs
sqlite3 -box -header kesinti.db 'SELECT COUNT(*) AS yeniden_acildiginda FROM odunc;'
rm -f kesinti.db
işlem içinde görülen satır: 1
┌─────────────────────┐
│ yeniden_acildiginda │
├─────────────────────┤
│ 0                   │
└─────────────────────┘

Süreç kendi işlemi içinde satırı gördü; veritabanı dosyası yeniden açıldığında satır yoktu. Tablo tanımı kalıcı oldu, çünkü CREATE TABLE işlem başlamadan önce otomatik kesinleştirme kipinde çalıştı.

Bu davranış, kesinleştirmenin bir eşik olduğunu gösterir: COMMIT dönmeden önce hiçbir şey söz verilmemiştir. Uygulama tarafında bunun karşılığı, işlemi açan kodun her çıkış yolunda — hata, erken dönüş, kesinti — işlemi kapatmasını güvenceye almaktır.

İşlemin Sınırını Belirlemek

İşlemin ne kadar geniş tutulacağı bir tasarım kararıdır ve iki yönlü baskı altındadır.

Dar tutulursa birlikte olması gereken değişiklikler ayrı işlemlere düşer ve arada kalan bir hata tutarsızlık bırakır. İşlemin sınırı, iş kuralının sınırıdır: “ödünç verme” işleminde kayıt açma ile raf durumu güncelleme aynı işlemde olmalıdır.

Geniş tutulursa işlem uzun süre açık kalır; tuttuğu kaynaklar başka bağlantıları bekletir ve geri alma maliyeti büyür. Kullanıcı girdisi beklerken açık işlem tutmak bu hatanın en bilinen biçimidir: veritabanı, kullanıcının yanıtını bekleyerek dakikalarca kilit tutabilir.

Bu iki baskının nasıl dengeleneceği kilitleme davranışı dersinde somutlaşacaktır. Şimdilik kural olarak: işlem, iş kuralının gerektirdiği en küçük deyim kümesini kapsar ve başladıktan sonra dış dünyayı beklemez.

Özet

  • Açık işlem başlatılmadan çalıştırılan her deyim kendi başına bir işlemdir; bu kipe otomatik kesinleştirme denir.
  • BEGIN ile açılan işlemde değişiklikler COMMIT çalıştırılana kadar kalıcı değildir; ROLLBACK işlem boyunca yapılmış tüm değişiklikleri birlikte siler.
  • Deyim hatası yalnız o deyimi etkisiz kılar; işlem açık kalır ve geri alma kararı uygulamaya aittir, hatadan sonra kesinleştirmek kısmi sonucu kalıcı yapar.
  • Kesinleştirilmemiş bir işlem, bağlantı sona erdiğinde geri alınır.
  • İşlemin sınırı iş kuralının sınırıdır; gereğinden geniş tutulan işlem kaynak tutar ve başka bağlantıları bekletir.

Sonraki Adım

Geri alma bu derste bir “tümünü sil” düğmesiydi: işlemin başına dönmekten başka seçenek yoktu. Toplu işlerde bu fazla kaba kalır — yüz kitabın envanter kaydı işlenirken üçüncüsü hatalıysa, ilk ikisini de atmak gereksizdir. Sonraki ders işlem içinde ara duraklar tanımlamayı, yalnız o duraktan sonrasını geri almayı ve iç içe geri alma noktalarının nasıl davrandığını gösterecek.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat