ACID garantilerinin veritabanı tasarımını ve uygulama davranışını nasıl etkilediğini öğrenin. Atomiklik, tutarlılık, izolasyon, kalıcılık, ödünleşimler ve gerçek örnekleri keşfedin.

Market alışverişi ödemeniz, uçuş rezervasyonu veya hesaplar arasında para transfer ederken sonucu net bekleriz: ya başarılı olur ya da olmaz. Veritabanları da aynı kesinliği sağlamaya çalışır—aynı anda birçok kişi sistemi kullanırken, sunucular çökerken veya ağda kesinti olunca bile.
İşlem, veritabanının tek bir “paket” olarak ele aldığı bir iş birimidir. Birden fazla adım içerebilir—envanteri azaltma, sipariş kaydı oluşturma, kartı tahsil etme ve makbuz yazma gibi—ama tek bir uyumlu eylem gibi davranması beklenir.
Herhangi bir adım başarısız olursa, sistem yarım kalmış bir iş bırakmak yerine güvenli bir noktaya geri sarılmalıdır.
Kısmi güncellemeler sadece teknik aksaklıklar değildir; müşteri destek biletlerine ve finansal riske dönüşür. Örneğin:
Bu hataların izini sürmek zordur çünkü her şey “çoğunlukla doğru” görünür, ama rakamlar tutmaz.
ACID, birçok veritabanının işlemler için sağlayabileceği dört garantiyi kısaca ifade eder:
Bu, belirli bir veritabanı markası veya tek bir açıp kapatılacak özellik değildir; davranış hakkında bir sözdür.
Daha güçlü garantiler genellikle veritabanının daha fazla iş yapmasını gerektirir: ekstra koordinasyon, kilitler için bekleme, versiyon takibi ve günlük yazma. Bu, yüksek yük altında verimliliği düşürebilir veya gecikmeyi artırabilir. Ama amaç her zaman "her zaman maksimum ACID" değil; iş risklerinizle uyumlu garantileri seçmektir.
Atomiklik, bir işlemin tek bir iş birimi olarak ele alınması demektir: ya tamamen biter ya da hiçbir etkisi olmaz. Veritabanında "yarım güncelleme" görünmez.
Alice'ten Bob'a 50$ aktarımı düşünün. Arkada genellikle en az iki değişiklik olur:
Atomiklik ile bu iki değişiklik beraber başarılır ya da beraber başarısız olur. Sistem her ikisini güvenli şekilde yapamıyorsa, hiçbiri yapılmamalıdır. Bu, Alice ücretlendirilip Bob'un parayı almaması gibi kabus senaryolarını önler.
Veritabanları işlemler için iki çıkış sunar:
Faydalı bir zihinsel model "taslak vs. yayınla"dır. İşlem çalışırken değişiklikler geçicidir. Sadece commit ile yayınlanırlar.
Atomiklik önemlidir çünkü hatalar normaldir:
Eğer bunlardan biri commit tamamlanmadan olursa, atomiklik veritabanının geri almasını sağlayarak kısmi çalışmaların kalıcı hâle gelmesini engeller.
Atomiklik veritabanı durumunu korur, ama uygulamanız belirsizlikle başa çıkmak zorundadır—özellikle ağ kesintileri komitin olup olmadığını belirsiz kıldığında.
Pratik tamamlayıcılar:
Atomik işlemler ve idempotent yeniden denemeler birlikte hem kısmi güncellemeleri hem de kazara çift ücretlendirmeyi önlemeye yardımcı olur.
ACID'teki tutarlılık, "veri makul görünsün" ya da "tüm replikalar eşleşsin" anlamına gelmez. Her işlem, veritabanını sizin tanımladığınız kuralların izin verdiği bir geçerli durumdan diğerine taşımalıdır.
Veritabanı, "geçerli"nin ne olduğunu tanımlayan açık kısıtlar, tetikleyiciler ve invariantlara göre tutarlılığı sağlayabilir. ACID bu kuralları icat etmez; işlemler sırasında bunları uygular.
Yaygın örnekler:
order.customer_id mevcut bir müşteriye işaret etmelidir.Bu kurallar varsa, veritabanı bunları ihlal edecek herhangi bir işlemi reddeder—böylece "yarım-geçerli" veri oluşmaz.
Uygulama düzeyinde doğrulama önemli ama tek başına yeterli değildir.
Klasik bir hata modu, uygulamada bir şeyi kontrol edip ("e-posta müsait"), sonra satırı eklemektir. Eşzamanlılık altında iki istek aynı anda kontrolü geçebilir. Veritabanındaki unique constraint sadece bir insert'in başarılı olmasını garanti eder.
"Negatif bakiye olamaz" kuralını bir kısıt olarak kodlarsanız (veya tek bir işlem içinde güvenilir şekilde uygularsanız), bir transfer hesabı eksiye düşürecekse tüm transferin başarısız olması gerekir. Eğer bu kuralı hiçbir yerde kodlamazsanız, ACID bunu koruyamaz—çünkü korunacak bir kural yoktur.
Tutarlılık nihayetinde açık olmaktır: kuralları tanımlayın, sonra işlemlerin bu kuralların asla bozulmamasını sağlayın.
İzolasyon, işlemlerin birbirinin üzerine basmasını önler. Bir işlem sürerken diğer işlemler yarım değişiklikleri görmemeli veya yanlışlıkla üstüne yazmamalıdır. Amaç basit: birçok kullanıcı aynı anda aktif olsa bile her işlem sanki yalnız çalışıyormuş gibi davranmalıdır.
Gerçek sistemler yoğundur: müşteriler sipariş verir, destek ajanları profilleri günceller, arka plan işleri ödemeleri uzlaştırır—hepsi aynı anda. Bu eylemler çakışır ve genellikle aynı satırlara dokunurlar (hesap bakiyesi, envanter adedi, rezervasyon slotu).
İzolasyon yoksa zamanlama iş mantığınızın bir parçası olur. "Envanteri azalt" güncellemesi başka bir ödeme işlemiyle yarışabilir veya bir rapor veriyi değişim ortasındayken okuyup asla var olmamış sayıları gösterebilir.
Tam anlamıyla "yalnızmış gibi davran" izolasyon pahalı olabilir. Throughput'u düşürebilir, beklemeleri artırabilir (kilitler) veya işlemlerin yeniden denenmesine yol açabilir. Oysa birçok iş akışı en katı korumaya ihtiyaç duymaz—örneğin dünün analitiğini okumak küçük tutarsızlıklara katlanabilir.
Bu yüzden veritabanları yapılandırılabilir izolasyon seviyeleri sunar: daha iyi performans ve daha az çatışma karşılığında ne kadar eşzamanlılık riskini kabul edeceğinizi seçersiniz.
İzolasyon çok zayıfsa aşağıdaki klasik anormalliklerle karşılaşırsınız:
Bu başarısızlık modlarını anlamak, işinizin beklentileriyle uyumlu bir izolasyon seviyesi seçmenizi kolaylaştırır.
İzolasyon, işleminiz çalışırken başka işlemlerin sizi hangi değişikliklerle "görmesine" izin verildiğini belirler. Zayıf izolasyon bir iş yükü için uygunsuzsa anormalliklerle karşılaşırsınız—kullanıcıları şaşırtan davranışlar teknik olarak mümkün hale gelir.
Dirty read: henüz commit edilmemiş bir işlemin yazdığı veriyi okumaktır.
Senaryo: Alex 500$ transfer ederken bakiye geçici olarak 200$ olur ve siz o 200$'ı okursunuz; sonra Alex'in transferi başarısız olup rollback olursa siz yanlış düşük bakiyeyi görmüş olursunuz.
Kullanıcı sonucu: müşteri yanlış düşük bakiye görür, sahtecilik kuralı yanlış çalışır veya destek yanlış bilgi verir.
Non-repeatable read: aynı satırı iki kere okuduğunuzda aradaki commit yüzünden farklı değerler alırsınız.
Senaryo: Bir sipariş toplamını ($49.00) yüklersiniz, sonra bir yenilemede $54.00 görürsünüz çünkü bir indirim satırı kaldırılmıştır.
Kullanıcı sonucu: "Toplamım kontrol ederken değişti" hissi, güvensizlik veya sepetten vazgeçme.
Phantom read: non-repeatable read'e benzer ama satır seti ile ilgilidir: başka bir işlem eşleşen kayıtlar eklediği veya sildiği için ikinci sorgu farklı satırlar döndürür.
Senaryo: Otel araması "3 oda mevcut" gösterir, rezervasyon sırasında sistem yeniden kontrol ettiğinde hiç oda kalmamıştır çünkü yeni rezervasyonlar eklenmiştir.
Kullanıcı sonucu: çift rezervasyon denemeleri, tutarsız uygunluk ekranları veya aşırı satış.
Lost update: iki işlem aynı değeri okur ve ikisi de güncelleme yazar; son yazan öncekinin değişikliğini siler.
Senaryo: İki yönetici aynı ürün fiyatını düzenler. İkisi de $10'dan başlar; biri $12 kaydeder, diğeri daha sonra $11 kaydeder.
Kullanıcı sonucu: birinin değişikliği kaybolur; raporlar yanlış çıkar.
Write skew: iki işlem ayrı ayrı geçerli bir değişiklik yapar ama birlikte bir kuralı bozar.
Senaryo: Kural: "En az bir nöbetçi doktor görevde olmalı." İki doktor birbirinin hâlâ görevde olduğunu kontrol edip aynı anda devre dışı kalmayı işaretler.
Kullanıcı sonucu: her biri kendi kontrolünü geçerken sonuçta görevde kimse kalmaz.
Daha güçlü izolasyon anormallikleri azaltır ama beklemeleri, yeniden denemeleri ve maliyetleri artırabilir. Birçok sistem okuma ağırlıklı analitik işler için daha zayıf izolasyon seçerken, para transferi, rezervasyon gibi doğruluk açısından kritik akışlar için daha katı ayarlar kullanır.
İzolasyon, işleminiz diğer işlemler sürerken neyi "görebilir" sorusunun cevabıdır. Veritabanları bunu izolasyon seviyeleri olarak sunar: daha yüksek seviye şaşırtıcı davranışları azaltır ama maliyeti olabilir.
Ekipler genellikle kullanıcıya yönelik uygulamalar için Read Committed'i varsayılan olarak seçer: iyi performans ve "kirli okumaların olmaması" beklentilerle uyumludur.
Repeatable Read işlem içinde sabit sonuçlara ihtiyaç duyduğunuzda (ör. bir fatura oluştururken) tercih edilir. Serializable ise doğruluğun eşzamanlılıktan daha önemli olduğu durumlar içindir (ör. envanterin asla aşılmaması).
Read Uncommitted OLTP sistemlerde nadirdir; bazen izleme veya yaklaşık raporlama için kabul edilebilir yanlış okumalar tolere ediliyorsa kullanılır.
İsimler standart olsa da tam garantiler veritabanı motoruna göre farklılık gösterebilir (hatta bazen konfigürasyona göre değişir). İlgili anormallikleri işiniz için test edin ve dokumentasyonu doğrulayın.
Kalıcılık, bir işlem commit edildiğinde sonuçlarının bir çöküş—güç kaybı, süreç yeniden başlatma veya ani makine yeniden başlaması—sonrasında bile korunacağını ifade eder. Uygulamanız bir müşteriye "ödeme başarılı" diyorsa, kalıcılık veritabanının bu sonucu unutmayacağını vaat etmesidir.
Çoğu ilişkisel veritabanı kalıcılığı write-ahead logging (WAL) ile sağlar. Yüksek düzeyde, veritabanı commit kabul etmeden önce değişikliklerin dizisel bir "makbuz"unu diske yazar. Çökme halinde, veritabanı başlatıldığında bu günlüğü oynatarak commit edilmiş değişiklikleri geri yükleyebilir.
Kurtarma süresini makul tutmak için veritabanları ayrıca checkpoint oluşturur. Checkpoint, veritabanının yeterli son değişikliği ana veri dosyalarına yazdığından emin olduğu bir andır, böylece kurtarma sonsuz miktarda günlük geçmişi oynatmak zorunda kalmaz.
Kalıcılık tek bir açık/kapalı düğmesi değildir; veritabanının veriyi kalıcı depolamaya ne kadar agresif zorladığına bağlıdır.
fsync). Bu daha güvenlidir ama gecikme ekleyebilir.Altyapı da önemlidir: SSD'ler, yazma önbellekli RAID denetleyicileri ve bulut hacimleri başarısızlık altında farklı davranabilir.
Yedekleme ve replikasyon kurtarmaya veya kesinti süresini azaltmaya yardımcı olur ama kalıcılığın kendisi değildir. Bir işlem birincilde kalıcı olsa bile replikaya henüz ulaşmamış olabilir; yedekler ise genellikle anlık görüntülerdir, commit bazlı garanti değildir.
BEGIN deyip sonra COMMIT ettiğinizde veritabanı birçok parçayı koordine eder: kim hangi satırları okuyabilir, kim güncelleyebilir ve aynı kaydı değiştirmek isteyen iki kişi olursa ne olur.
Çatışmaları ele almanın temel bir seçimi vardır:
Birçok sistem iş yükü ve izolasyon seviyesine göre her iki yaklaşımı harmanlar.
Modern veritabanları genellikle MVCC (Çok-Sürümlü Eşzamanlılık Kontrolü) kullanır: veritabanı sadece bir satırın tek kopyasını tutmak yerine birden çok sürüm tutar.
Bu, bazı veritabanlarının çok sayıda okuma ve yazmayı daha az bloklamayla yönetebilmesinin önemli nedenidir—ama yazma/yazma çatışmaları yine çözülmelidir.
Kilitler deadlock'lara yol açabilir: İşlem A, B'nin tuttuğu kilidi beklerken B de A'nın tuttuğu kilidi bekleyebilir. Veritabanları genelde döngüyü tespit edip bir işlemi sonlandırır ("deadlock victim"), uygulamaya hata döner ve uygulama yeniden denemelidir.
ACID uygulanması sürtünme yaratıyorsa genellikle şunları görürsünüz:
Bu semptomlar genellikle işlem boyutunu, indekslemeyi veya hangi izolasyon/kilit stratejisinin uygun olduğunu yeniden gözden geçirmenin zamanı olduğunu gösterir.
ACID garantileri sadece veritabanı teorisi değildir—API'lerinizi, arka plan işlerinizi ve hatta kullanıcı arayüzü akışlarınızı nasıl tasarladığınızı etkiler. Temel fikir basit: hangi adımların birlikte başarılı olması gerektiğine karar verin ve yalnızca o adımları bir işlem içinde sarın.
İyi bir işlemsel API genellikle bir iş eylemine karşılık gelir; birden fazla tabloyu etkiliyor olsa bile. Örneğin /checkout işlemi bir sipariş oluşturabilir, envanteri rezerve edebilir ve bir ödeme niyeti kaydedebilir. Bu veritabanı yazmaları genellikle tek bir işlemde olmalıdır ki hepsi birlikte commit olsun ya da hiçbiri.
Yaygın bir desen:
Bu, atomiklik ve tutarlılığı korurken yavaş, kırılgan işlemlerden kaçınır.
İşlem sınırlarını nerede koyacağınız "bir iş birimi"nin ne anlama geldiğine bağlıdır:
ACID yardımcı olur ama uygulamanız yine de hataları doğru ele almalıdır:
Uzun işlemler, işlem içinde harici API çağrıları ve kullanıcı düşünme süresini işlem içinde bekletme (ör. "sepet satırını kilitle, kullanıcı onaylasın") gibi uygulamalardan kaçının. Bunlar içeriği artırır ve izolasyon çatışmalarını çok daha olası kılar.
Hızlıca işlemsel bir sistem kuruyorsanız en büyük risk genellikle "ACID'i bilmemek" değil, bir iş eylemini birden çok uç noktaya, işe veya tabloya dağınık şekilde yaymak ve işlem sınırlarını belirsiz bırakmaktır.
Koder.ai gibi platformlar ACID etrafında tasarlarken hız kazandırabilir: örneğin bir iş akışını ("envanter rezervasyonu ve ödeme niyeti ile checkout") plan odaklı bir sohbetle tarif edebilir, React UI ile Go + PostgreSQL arka ucunu üretebilir ve şema veya işlem sınırı değişikliklerini anlık görüntü ve geri alma ile yineleyebilirsiniz. Veritabanı garantileri hâlâ uygulanır; değer doğru tasarımdan çalışan bir uygulamaya geçiş hızındadır.
Tek bir veritabanı genellikle bir işlem sınırı içinde ACID garantilerini sağlayabilir. İşleri birden çok hizmete (ve genellikle birden çok veritabanına) yaydığınızda aynı garantileri korumak zorlaşır—ve bunları korumak pahalılaşır.
Sıkı tutarlılık, her okumanın "en son commit edilmiş gerçekliği" görmesi demektir. Yüksek kullanılabilirlik ise parçalar yavaş veya erişilemez olsa bile sistemin yanıt vermeye devam etmesidir.
Çok hizmetli bir yapıda geçici ağ problemi sizi bir seçim yapmaya zorlayabilir: tüm katılımcılar anlaşana kadar istekleri bloklamak veya reddetmek (daha tutarlı, daha az kullanılabilir) ya da hizmetlerin kısa süreli olarak uyumsuz olmasını kabul etmek (daha kullanılabilir, daha az tutarlı). Hiçbiri her zaman doğru değildir—işinizin hangi hataları tolere edebileceğine bağlıdır.
Dağıtık işlemler, tam kontrolünüzde olmayan sınırlar arasında koordinasyon gerektirir: ağ gecikmeleri, yeniden denemeler, zaman aşımı, servis çökmeleri ve kısmi hatalar. Tüm servisler düzgün olsa bile ağ belirsizlik yaratabilir: ödeme servisi commit etti ama sipariş servisi onayı hiç almadı mı? Güvenli çözüm için iki aşamalı commit gibi koordinasyon protokolleri kullanılır; bunlar yavaş olabilir, arıza durumunda kullanılabilirliği azaltabilir ve işletme karmaşıklığını artırır.
Sagas: Bir iş akışını adımlara böler; her adım yerel olarak commit edilir. Daha sonra bir adım başarısız olursa önceki adımlar telafi edici işlemlerle geri alınır (ör. ücreti iade etme).
Outbox/inbox: Olay yayınlama ve tüketmeyi güvenilir kılar. Bir servis iş verisini ve "yayınlanacak olay" kaydını aynı yerel işlem içinde (outbox) yazar. Tüketiciler işlenmiş mesaj ID'lerini (inbox) kaydeder, böylece yeniden denemelerde çoğaltmayı önlerler.
Nihai tutarlılık (Eventual consistency): Hizmetler arasında kısa süreli farklılıkları kabul eder ve uzlaşma için net bir planı olur.
Garantileri gevşetin quando:
Riski kontrol edin:
Gerçekten kritik invariantlar (ör. "bir hesabı asla aşmama") için mümkünse bunları tek bir servis ve tek bir veritabanı işlemi içinde tutun.
Bir işlem birim testinde "doğru" olsa bile gerçek trafiğe, yeniden başlatmalara ve eşzamanlılığa maruz kaldığında başarısız olabilir. ACID garantilerini üretimdeki davranışla hizalamak için bu kontrol listesini kullanın.
Önce her zaman doğru olması gerekenleri yazın (veri invariantlarınız). Örnekler: "hesap bakiyesi hiçbir zaman negatif olamaz", "sipariş toplamı kalemlerin toplamına eşit olmalı", "envanter sıfırın altına düşemez", "bir ödeme tam olarak bir siparişe bağlanmalıdır." Bunları ürün kuralları olarak ele alın.
Sonra hangi adımların tek bir işlem içinde olması gerektiğine karar verin vs. hangi adımların ertelenebileceğine.
İşlemleri küçük tutun: daha az satıra dokunun, daha az iş yapın (harici API çağrısı yok), ve hızlı commit edin.
Eşzamanlılığı birinci sınıf test boyutu yapın.
Yeniden denemeleri destekliyorsanız açık bir idempotentlik anahtarı ekleyin ve "başarıdan sonra istek tekrarlandığında" testi yapın.
Garantilerinize sürtünme getirdiğini gösteren göstergeleri izleyin:
Trend tabanlı uyarılar oluşturun ve bu metrikleri onları tetikleyen uç nokta veya işlerle ilişkilendirin.
İnvariantlarınızı koruyacak en zayıf izolasyonu kullanın; varsayılan olarak "her şeyi maksimuma çekmeyin". Küçük kritik bölüm (para transferi, envanter azaltma) için katı doğruluk gerektiğinde, işlemi sadece o bölümle sınırlayın ve geri kalan her şeyi dışarıda tutun.
ACID, veritabanlarının arızalar ve eşzamanlılık altında öngörülebilir davranmasını sağlayan işlem garantilerinin bir grubudur:
Bir işlem, veritabanının tek bir paket olarak ele aldığı "birimler halindeki iş"tir. Birkaç SQL deyimi çalıştırsa bile (ör. sipariş oluşturma, envanteri azaltma, ödeme niyeti kaydetme) yalnızca iki sonucu vardır:
Kısmi güncellemeler gerçek dünyada çelişkiler yaratır ve sonradan düzeltmesi pahalıdır; örneğin:
ACID (özellikle atomiklik + tutarlılık) bu “yarım kalmış” durumların gerçeğe dönüşmesini engeller.
Atomiklik, veritabanının "yarım tamamlanmış" bir işlemi asla açığa çıkarmamasını garantiler. Commit tamamlanmadan önce bir hata olursa—uygulama çökmesi, ağ kesintisi, DB yeniden başlatması—işlem geri alınır ve önceki adımlar kalıcı hâle gelmez.
Pratikte atomiklik, iki bakiyeyi güncelleyen bir transfer gibi çok adımlı değişiklikleri güvenli kılar.
Bir commit olup olmadığını bazen istemci bilemeyebilir (ör. commit sonrası ağ zaman aşımı). Bu yüzden ACID yeterli olsa da uygulamanız yine de şunları kullanmalıdır:
Böylece hem kısmi güncellemeler hem de kazara çift ücretlendirme/duble yazma engellenir.
ACID'teki “tutarlılık”, verinin makul görünmesi veya tüm replikaların aynı olması demek değildir. Her işlem, veritabanını sizin tanımladığınız kurallara göre bir geçerli durumdan diğerine taşımak zorundadır—yani kısıtlar, tetikleyiciler ve invariantlar önemlidir.
Eğer bir kuralı (ör. "bakiye negatif olamaz") hiçbir yerde kodlamazsanız, ACID bunun için koruma sağlayamaz. Veritabanı, açıkça tanımlanmış kurallara göre işlem yapar.
Uygulama düzeyinde doğrulama kullanıcı deneyimini iyileştirir ama eşzamanlılık altında yetersiz kalabilir (ör. iki istek aynı anda "email müsait" kontrolünü geçebilir). Veritabanı kısıtlamaları son savunma hattıdır:
İkisini birlikte kullanın: uygulamada erken doğrulama, veritabanında kesin zorlama.
İzolasyon, işleminiz diğerleri çalışırken ne görebileceğini kontrol eder. Zayıf izolasyon şu anomallere yol açabilir:
İzolasyon seviyeleri performans ile koruma arasında seçim yapmanızı sağlar.
Bir pratik varsayılan birçok OLTP uygulaması için Read Committed'tir: kirli okumaları engeller ve performansı iyi tutar. Gerektikçe daha güçlü seviyelere geçin:
Her zaman veritabanı motorunuzdaki davranışı doğrulayın; isimler standart olsa da garantiler motorlar arasında farklılık gösterebilir.
Kalıcılık, veritabanı bir commit doğruladıktan sonra değişikliğin çöküşlerden sonra da kalacağını garanti eder. Çoğu ilişkisel veritabanı bunu write-ahead logging (WAL) ile sağlar: değişikliklerin dizisel bir günlük kaydı diske yazılır ve ardından commit kabul edilir. Başka önemli noktalar:
Yedekleme ve replikasyon kurtarmaya yardım eder ama kalıcılık garantisinin ta kendisi değildir.