Ana içeriğe geç
Kesit SQL
Orta · Uygulama Geliştirme

Eşzamanlılık uygulaması: çift rezervasyon, FOR UPDATE, SKIP LOCKED

Aynı satırı iki istek aynı anda değiştirirse ne olur; koşullu güncelleme, satır kilidi, iş kuyruğu ve yeniden deneme.

Uygulamada aç, 4 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

İki kullanıcı son koltuğu aynı anda alıyor. İki istek de “stok 1” okuyor, ikisi de satış yapıyor: çift rezervasyon. Sorun SQL'in yanlış yazılması değil, okuma ile yazma arasındaki boşluk. Bu derste bu boşluğu kapatmanın dört yolunu görürsün.

Bu tarayıcıda deneyemezsinBuradaki motorda tek bağlantı var, yani gerçek eşzamanlılık yok. Kilit örnekleri bu yüzden çalıştırılabilir kutuda değil. Sözdizimini PostgreSQL'de doğruladık; davranışı kendi sunucunda iki oturum açarak dene.

1. Tek ifadede koşullu güncelleme

Çoğu durumda en basit ve en güvenli yol budur. Okumayı ve yazmayı tek ifadede birleştir, sonra etkilenen satır sayısına bak: 0 ise stok bitmiştir.

UPDATE products SET stock = stock - 1 WHERE product_id = 7 AND stock >= 1;

2. Kötümser kilit: FOR UPDATE

Okuduğun değere göre uygulamada karar vereceksen satırı okurken kilitle. İkinci oturum, birincisi işlemi bitirene kadar bekler.

BEGIN;
SELECT stock FROM products WHERE product_id = 7 FOR UPDATE;
-- uygulama kararını verir
UPDATE products SET stock = stock - 1 WHERE product_id = 7;
COMMIT;
SQL türüSatırı kilitleyerek okumaKilitli satırı atlama
PostgreSQL, MySQL 8+, OracleFOR UPDATEFOR UPDATE SKIP LOCKED
SQL ServerWITH (UPDLOCK, ROWLOCK)WITH (UPDLOCK, READPAST)
SQLite, BigQueryYokYok

3. İş kuyruğu: SKIP LOCKED

Birden çok işçi aynı kuyruktan iş çekiyorsa FOR UPDATE onları sıraya dizer. SKIP LOCKED kilitli satırı atlar, her işçi boşta olan bir sonraki işi alır.

BEGIN;
SELECT job_id FROM jobs
WHERE status = 'bekliyor'
ORDER BY job_id
LIMIT 1
FOR UPDATE SKIP LOCKED;
UPDATE jobs SET status = 'calisiyor' WHERE job_id = :secilen;
COMMIT;

4. İyimser kilit ve yeniden deneme

Çakışma seyrekse kilit tutmak yerine sürüm sütunu kullan: UPDATE ... SET surum = surum + 1 WHERE id = :id AND surum = :okunan. Etkilenen satır 0 ise başkası önce davranmıştır; yeniden oku ve dene.

Deadlock ve serileştirme hataları normaldir, kod bunlara hazır olmalı: PostgreSQL 40P01 ve 40001, SQL Server 1205 döndürür. İşlemi baştan, az sayıda ve kısa beklemeyle yeniden dene. Tek ifadenin bir bölümünü değil, bütün işlemi tekrarla.

Hangisini seçmeli?Tek satır ve basit koşul: koşullu UPDATE. Uygulama kararı gerekiyor: FOR UPDATE, işlemi kısa tut. Birden çok işçi: SKIP LOCKED. Çakışma seyrek, işlem uzun: sürüm sütunu.
Alıştırmalara geç (4)