Modül dersleri (2/4)
Yarış koşulları
Bir veritabanının tek bir terminalde yalıtılmış olarak nasıl çalıştığını anlamak basittir, ancak gerçek bir web senaryosunda istek gönderen yüzlerce eşzamanlı "Node/PHP/Go" işlemi olacaktır. Ünlü Yarış Koşullarının doğduğu yer burasıdır.
"Kayıp Güncelleme" sorunu
Kayıp Güncelleme, iki iş parçacığının aynı eski satırı okuduğunda, JavaScript sunucusunda bunun üzerinde biraz matematik yaptığında ve ardından sonucu kaydetmek için GÜNCELLEME'yi geri gönderdiğinde meydana gelir.
Senaryo:
- #5 ürününde 10 adet bulunmaktadır.
- A Kullanıcısı bir tane satın alır (Sunucu A "10"u okur, "9"u hesaplar).
- Aynı milisaniye içinde B kullanıcısı, A'nın satın alma işlemi COMMIT aşamasını tamamlamadan önce başka bir satın alır.
- Sunucu B ayrıca "10"u okur, "9"u hesaplar.
- A Sunucusu
UPDATE: set quantity = 9gönderir. - B Sunucusu
UPDATE: set quantity = 9gönderir. - Her ikisi de sayıyı başarılı bir şekilde azalttıklarını düşünüyor. Ancak nihai değerin 8 birim olması gerekirdi! Hayali bir satın alma işlemi kaybedildi.
Ağır işlemler gerektirmeyen çözüm (Atomik Güncellemeler)
Matematiği dışarıda okuyup yapmak yerine, DB'nin bunu her zaman senkronize olan güncelleme sırasında yapmasına izin verin.
-- Wrong
UPDATE products SET stock = 9 WHERE id = 5;
-- Correct and natively thread-safe
UPDATE products SET stock = stock - 1 WHERE id = 5;Daha aşırı anormallikler (Kirli Okumalar ve Hayaletler)
- Kirli Okuma: Başka birinin henüz bir COMMIT tarafından onaylanmamış geçici verilerini okudunuz (ve aniden sizi geçersiz kılan ROLLBACK'e gidebilir).
- Hayalet Okumalar: Tüm satırları tararsınız, bu arada ikinci bir iş parçacığı yeni bir kayıt ekler, ardından aynı işlem sırasında başka bir tarama yaparsınız ve sihirli bir şekilde yeni kaydın birdenbire ortaya çıktığını ve hesaplanmış mali raporlardan ödün verdiğini görürsünüz.
Küçük bir dize manipülasyonu için müşteri kaydını atomik olarak değiştirin.\nDiyelim ki bir müşterinin 'şehrini' yıldız işareti ekleyerek yeniden adlandırmak istiyoruz. \nBunu, kimliği=10 olan satır için satırın kendi değerinden yararlanarak, ' - Eski'yi geçerli değere birleştirerek yapın (postgres' || birleştirme borusunu kullanın).
İpucu göster
GÜNCELLEME müşteriler şehir = şehir || ' - Eski' WHERE kimliği = 10;
3 denemeden sonra çözüm mevcut
Ödemelerde ve fiyatlarda klasik bir kayıp güncelleme meydana gelir.\nDiyelim ki acil bir fiyat artışı oldu: 'order_items' tablosunun 'unit_price' değerini (sipariş 1'in ürün 1'i için) atomik olarak %20 artırın, yani JS'de önceden manuel olarak hesaplanan yeni fiyatı eklemek yerine * 1,2 ile çarpın.
İpucu göster
GÜNCELLE order_items SET birim_fiyat = birim_fiyat * 1.2 WHERE sipariş_id = 1 VE ürün_id = 1;
3 denemeden sonra çözüm mevcut