---
title: 'Yalıtım Düzeylerinin Uygulama Etkisi'
source: 'https://academia.sh/tr/kurslar/veri-erisim-katmani/yalitim-duzeylerinin-uygulama-etkisi'
course: 'Veri Erişim Katmanı ve İş Mantığı'
language: tr
updated: '2026-08-17T18:06:51+00:00'
license: 'CC BY-SA 4.0'
---

# Yalıtım Düzeylerinin Uygulama Etkisi

Okuma anomalilerinin uygulamadan görünümü: aynı sorgunun iki kez çalıştırılmasıyla tekrarlanamayan okuma ve hayalet satırın ölçülmesi, iki toplama sorgusu arasındaki değişmezin binlerce örnekte ihlal edilmesi ve yalıtımın bedeli.

Önceki ders iki bağlantının aynı satıra yazmak istemesini ve birinin ötekini beklemesini
ölçtü. Yazma–yazma çakışması görünür bir olaydır: biri bekler, sonra yazar. Okuma tarafında
olanlar sessizdir.

Bir işlem sürerken başka bir bağlantı aynı satırları okursa ne görür? Değişikliğin öncesini
mi, sonrasını mı, yoksa sorgudan sorguya değişen bir karışımı mı? Yanıt yalıtım düzeyine
bağlıdır. İleri SQL kursunda düzeyler ve izin verdikleri anomaliler tanımlandı; bu ders aynı
anomalileri uygulama kodundan ölçer ve düzeyin seçilmesinin uygulamada ne anlama geldiğini
gösterir.

## Düzenek

Şema küçüktür: bir üye, beş kitap, ödünç kayıtları.

```sh
# kur.sh — dersin veritabanini ve isaret dosyalarini sifirlar
rm -f kutuphane.db kutuphane.db-wal kutuphane.db-shm okundu yazildi
sqlite3 kutuphane.db >/dev/null <<'SQL'
PRAGMA journal_mode = WAL;
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, odunc_siniri INTEGER NOT NULL);
CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL,
                    durumu TEXT NOT NULL CHECK (durumu IN ('rafta','odunc')));
CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL,
                    uye_id INTEGER NOT NULL, iade_tarihi TEXT);
INSERT INTO uye VALUES (4,'Emre',3);
INSERT INTO kitap VALUES (1,'Körlük','rafta'),(2,'Tutunamayanlar','rafta'),
  (3,'Kum Kitabı','rafta'),(4,'Yaban','rafta'),(5,'Sessiz Ev','rafta');
SQL
```

İki süreç birbirini işaret dosyalarıyla bekler. Bu, zamanlamayı rastlantıya bırakmadan
belirli bir sıralamayı üretmenin en küçük yoludur.

## İki Anomali, Tek Senaryo

Okuyucu aynı iki sorguyu iki kez çalıştırır: bir satırın değerini ve bir bağıntının satır
sayısını. Arada yazıcı devreye girer.

```js
// okuyucu.mjs — ayni iki sorguyu iki kez calistirir; kip: otomatik | islem
import { DatabaseSync } from "node:sqlite";
import { writeFileSync, existsSync } from "node:fs";

const kip = process.argv[2];
const db = new DatabaseSync("kutuphane.db");
const oku = () => ({
  sinir: db.prepare("SELECT odunc_siniri AS s FROM uye WHERE uye_id = 4").get().s,
  kitap: db.prepare("SELECT count(*) AS n FROM kitap").get().n,
});

if (kip === "islem") db.exec("BEGIN");
const ilk = oku();
writeFileSync("okundu", "");
while (!existsSync("yazildi")) { /* yazicinin kesinlestirmesini bekle */ }
const ikinci = oku();
if (kip === "islem") db.exec("COMMIT");

console.log(`kip=${kip}`);
console.log(`  ilk okuma   : sinir=${ilk.sinir}  kitap=${ilk.kitap}`);
console.log(`  ikinci okuma: sinir=${ikinci.sinir}  kitap=${ikinci.kitap}`);
console.log(`  tekrarlanamayan okuma: ${ilk.sinir !== ikinci.sinir}`);
console.log(`  hayalet satir        : ${ilk.kitap !== ikinci.kitap}`);
```

```js
// yazici.mjs — okuyucunun ilk okumasindan sonra guncelleyip yeni satir ekler
import { DatabaseSync } from "node:sqlite";
import { writeFileSync, existsSync } from "node:fs";

while (!existsSync("okundu")) { /* okuyucunun ilk okumasini bekle */ }
const db = new DatabaseSync("kutuphane.db");
db.exec("BEGIN IMMEDIATE");
db.prepare("UPDATE uye SET odunc_siniri = 5 WHERE uye_id = 4").run();
db.prepare("INSERT INTO kitap VALUES (6,'Anayurt Oteli','rafta')").run();
db.exec("COMMIT");
writeFileSync("yazildi", "");
console.log("yazici: sinir 5 yapildi, yeni kitap eklendi");
```

Aynı senaryo iki kipte çalıştırılır. `otomatik` kipinde okuyucu hiçbir işlem açmaz; her
sorgu kendi başına yürür. `islem` kipinde iki okuma tek bir işlem sınırının içindedir.

```sh
# deney.sh — ayni senaryo iki kipte
for kip in otomatik islem; do
  sh kur.sh
  node yazici.mjs >/dev/null &
  yazici=$!
  node okuyucu.mjs $kip
  wait $yazici
  echo
done
```

```sh
sh deney.sh
```

```
kip=otomatik
  ilk okuma   : sinir=3  kitap=5
  ikinci okuma: sinir=5  kitap=6
  tekrarlanamayan okuma: true
  hayalet satir        : true

kip=islem
  ilk okuma   : sinir=3  kitap=5
  ikinci okuma: sinir=3  kitap=5
  tekrarlanamayan okuma: false
  hayalet satir        : false
```

İki anomali de ilk kipte göründü. `odunc_siniri` değeri 3'ten 5'e döndü: aynı satır, aynı
sorgu, farklı sonuç. Buna **tekrarlanamayan okuma** denir. Kitap sayısı 5'ten 6'ya çıktı:
sorgu aynı koşulu sordu, sonuç kümesine yeni bir satır girdi. Buna **hayalet satır** denir.
İkisinin farkı, birincisinin var olan bir satırın değerinde, ikincisinin sonuç kümesinin
üyeliğinde olmasıdır.

İkinci kipte iki okuma da ilk anın görüntüsünü verdi. İşlem açıldığında okuyucu bir **anlık
görüntü** üzerinde çalışır ve o görüntü işlem boyunca sabit kalır.

Buradaki asıl gözlem uygulamayla ilgilidir. Kod iki kipte de aynı sorguları çalıştırdı;
değişen tek şey bir `BEGIN` çağrısı oldu. **Uygulamanın gördüğü yalıtım düzeyi, okumaların
işlem sınırına alınıp alınmamasıyla belirlenir.** Sorguları sınırsız çalıştıran bir servis,
motorun sunduğu düzey ne olursa olsun, ardışık iki okuma arasında tutarlılık göremez.

## Değişmezin İhlal Oranı

Yukarıdaki senaryo zamanlamayı elle kurdu. Gerçek yükte zamanlama kurulmaz, rastlantıya
kalır. Bu durumda anomali "olur mu" değil "ne sıklıkla olur" sorusuna dönüşür.

Kütüphanede tutulması gereken bir **değişmez** var: ödünçte görünen kitap sayısı, iade
edilmemiş ödünç kaydı sayısına eşit olmalı. Yazıcı bu değişmezi hiç bozmuyor; her adımı tek
bir işlemde yapıyor.

```js
// dolasan-yazici.mjs — kitaplari surekli odunc verip iade eder; her adim tek islem
import { DatabaseSync } from "node:sqlite";
import { writeFileSync, rmSync } from "node:fs";

const db = new DatabaseSync("kutuphane.db");
db.exec("PRAGMA busy_timeout = 5000");
const bitis = Date.now() + Number(process.argv[2] ?? 1500);
writeFileSync("yaziyor", "");
let adim = 0;
while (Date.now() < bitis) {
  const kitapId = (adim % 5) + 1;
  db.exec("BEGIN IMMEDIATE");
  const durum = db.prepare("SELECT durumu FROM kitap WHERE kitap_id = ?").get(kitapId).durumu;
  if (durum === "rafta") {
    db.prepare("UPDATE kitap SET durumu = 'odunc' WHERE kitap_id = ?").run(kitapId);
    db.prepare("INSERT INTO odunc (kitap_id, uye_id, iade_tarihi) VALUES (?,4,NULL)").run(kitapId);
  } else {
    db.prepare("UPDATE kitap SET durumu = 'rafta' WHERE kitap_id = ?").run(kitapId);
    db.prepare(`UPDATE odunc SET iade_tarihi = '2025-07-25'
                WHERE odunc_id = (SELECT max(odunc_id) FROM odunc
                                  WHERE kitap_id = ? AND iade_tarihi IS NULL)`).run(kitapId);
  }
  db.exec("COMMIT");
  adim += 1;
}
rmSync("yaziyor");
console.log(`yazici: ${adim} islem kesinlestirdi`);
```

Okuyucu değişmezi sürekli örnekler ve kaç örnekte bozuk gördüğünü sayar.

```js
// tutarsizlik-say.mjs — iki toplama sorgusu arasindaki degismezi orneklerle sinar
import { DatabaseSync } from "node:sqlite";
import { existsSync } from "node:fs";

const kip = process.argv[2];
const db = new DatabaseSync("kutuphane.db");
db.exec("PRAGMA busy_timeout = 5000");
while (!existsSync("yaziyor")) { /* yazicinin baslamasini bekle */ }

let ornek = 0, ihlal = 0;
while (existsSync("yaziyor")) {
  if (kip === "islem") db.exec("BEGIN");
  const oduncteKitap = db.prepare("SELECT count(*) AS n FROM kitap WHERE durumu = 'odunc'").get().n;
  const acikKayit = db.prepare("SELECT count(*) AS n FROM odunc WHERE iade_tarihi IS NULL").get().n;
  if (kip === "islem") db.exec("COMMIT");
  ornek += 1;
  if (oduncteKitap !== acikKayit) ihlal += 1;
}
console.log(`kip=${kip}  ornek=${ornek}  degismez ihlali=${ihlal}`);
```

```sh
# degismez.sh — ayni degismez iki okuma kipinde ornekleniyor
for kip in otomatik islem; do
  sh kur.sh
  rm -f yaziyor
  node tutarsizlik-say.mjs $kip &
  okuyucu=$!
  node dolasan-yazici.mjs 1500
  wait $okuyucu
done
```

```sh
sh degismez.sh
```

```
yazici: 29188 islem kesinlestirdi
kip=otomatik  ornek=17277  degismez ihlali=3327
yazici: 23632 islem kesinlestirdi
kip=islem  ornek=17446  degismez ihlali=0
```

Sayılar makineye ve o andaki yüke göre değişir; bir buçuk saniyede kaç işlem
kesinleştirileceği sabit değildir. Değişmeyen ayrımdır: sınırsız okumada on yedi bin
örneğin üç binden çoğu değişmezi bozuk gördü, işlem içinde okumada hiçbiri bozuk görmedi.

Oran yaklaşık beşte bir. Bu, ilgili raporun beş çağrıdan birinde tutarsız bir çift sayı
döndürmesi demektir. Hata kütüğüne hiçbir şey düşmez; sorgular başarılıdır, kısıt ihlali
yoktur, yalnız iki sayı birbirini tutmaz.

## Düzeylerin Uygulamadaki Karşılığı

İleri SQL kursunda dört anomali sıralanmıştı: kirli okuma, tekrarlanamayan okuma, hayalet
satır ve seri hâle getirilebilirlik ihlalleri. Uygulama tarafında bunların karşılığı üç
soruya iner.

**Hangi sorgular birlikte anlamlıdır?** Birlikte anlamlı olan sorgular aynı işlem sınırının
içine alınır. Yukarıdaki iki toplama sorgusu birlikte anlamlıydı; ayrı çalıştıklarında
ürettikleri çift anlamsız oldu.

**Okunan değer üzerine karar veriliyor mu?** Okunan değere bakıp bir yazma yapılıyorsa,
okuma ile yazma arasındaki aralıkta o değerin değişmemesi gerekir. Ödünç sınırını okuyup
"yer var" diyerek yazan bir servis, aradaki değişikliğe karşı korunmalıdır. Bu, yalıtım
düzeyinin tek başına çözmediği bir sorundur ve sonraki dersin konusudur.

**Bayat veriye tahammül var mı?** Anlık görüntü tutarlıdır ama günceldir demek değildir.
İşlem uzun sürerse, okuduğu veri kesinleşme anında eskimiş olabilir. Uzun raporlar için bu
kabul edilir; para hareketi gibi işler için edilmez.

Yalıtımın bedeli de bu üçüncü noktada durur. Yüksek düzey, ya kilit tutarak ötekileri
bekletir ya da eski sürümleri saklayarak depolama ve temizlik maliyeti üretir. İlişkisel
Veritabanı Yönetimi kursunda çok sürümlü eşzamanlılık denetimi olarak geçen mekanizma bu
ikinci yolu izler: eski sürümler bir okuyucu onlara ihtiyaç duyduğu sürece silinemez, uzun
açık kalan okuma işlemleri temizliği geciktirir.

## Özet

- Aynı iki sorgu, sınırsız çalıştığında değeri değişmiş bir satır (tekrarlanamayan okuma)
  ve sonuç kümesine giren yeni bir satır (hayalet satır) gördü; işlem sınırı içinde ikisi de
  görünmedi.
- Uygulamanın gördüğü yalıtım düzeyi, okumaların işlem sınırına alınıp alınmamasıyla
  belirlenir; kod aynı kalırken tek bir `BEGIN` çağrısı sonucu değiştirdi.
- İki toplama sorgusu arasındaki değişmez, sınırsız okumada on yedi bin örneğin yaklaşık
  beşte birinde bozuk göründü; işlem içinde okumada hiç bozulmadı.
- Bu tür tutarsızlık hata üretmez: sorgular başarılıdır, yalnız birlikte anlamsızdırlar.
- Yüksek yalıtımın bedeli bekleme ya da eski sürümlerin saklanmasıdır; uzun açık okuma
  işlemleri temizliği geciktirir.

## Sonraki Adım

Yalıtım, okunan verinin tutarlı olmasını sağlar; okunan değere dayanarak yapılan yazmanın
doğruluğunu garanti etmez. İki üye aynı anda son kalan kopyayı ödünç almak isterse, ikisi de
"kitap rafta" görür, ikisi de yazar ve biri ötekinin sonucunu geçersiz kılar. Bu çatışmayı
çözmenin iki yolu vardır: değişikliği yazarken kaydın hâlâ okunduğu hâlde olduğunu sınamak
ya da okuma anında kaydı kilitleyip ötekini beklemek. Sonraki ders iki yolu da kurar, çatışma
üretir, kilit hatasını birebir gösterir ve hangi yükte hangisinin daha ucuz olduğunu ölçer.
