Daha önce MySQL'de böyle bir eşzamanlılık problemini duymuştum. Postgres'de böyle değil.
Varsayılan READ COMMITTED
işlem yalıtım düzeyindeki yerleşik satır düzeyi kilitler yeterlidir.
Veri değiştiren CTE (MySQL'in sahip olmadığı bir şey) ile tek bir ifade öneriyorum çünkü değerleri bir tablodan diğerine doğrudan geçirmek uygun (buna ihtiyacınız varsa). coupon
Tablodan herhangi bir şeye ihtiyacınız yoksa, ayrı UPDATE
ve INSERT
ifadeleri olan bir işlemi de kullanabilirsiniz .
WITH upd AS (
UPDATE coupon
SET used = true
WHERE coupon_id = 123
AND NOT used
RETURNING coupon_id, other_column
)
INSERT INTO log (coupon_id, other_column)
SELECT coupon_id, other_column FROM upd;
Birden fazla işlemin aynı kuponu kullanmaya çalışması nadir görülen bir şey olmalıdır . Benzersiz bir sayıları var, değil mi? Aynı anda çalışmakta olan birden fazla işlemin daha nadir olması gerekir. (Belki bir uygulama hatası veya sistemi oynamaya çalışan biri?)
Ne olursa olsun , UPDATE
sadece tam olarak bir işlem için başarılı olur . Bir , güncellenmeden önce her hedef satırda UPDATE
bir satır düzeyinde kilit alır. Eşzamanlı bir işlem UPDATE
aynı satıra çalışırsa, satırdaki kilidi görür ve engelleme işlemi bitinceye ( ROLLBACK
veya COMMIT
) kadar bekler , ardından kilit kuyruğundaki ilk işlem olur :
Taahhüt edilirse, durumu tekrar kontrol edin. Hala devam ediyorsa NOT used
, satırı kilitleyin ve devam edin. Else UPDATE
artık hiçbir eleme satır bulur ve yapar bir şey bu yüzden, hiçbir satır döndüren, INSERT
ayrıca hiçbir şey yapmaz.
Geri alınırsa, satırı kilitleyin ve devam edin.
Orada bir yarış durumu için herhangi bir potansiyel .
Orada bir imkanı yok çıkmaz , aynı tür bir işlemi daha yazıyor koyabilir veya sadece birden fazla satır kilitlemek sürece.
INSERT
Bakım gerektirmez. Bazı durumlarda yanlışlıkla coupon_id
zaten log
tablodaysa (ve EŞSİZ veya PK kısıtlamanız varsa log.coupon_id
), tüm işlem benzersiz bir ihlalden sonra geri alınır. DB'nizde geçersiz bir durumu gösterir. Yukarıdaki ifade log
tabloya yazmanın tek yolu ise , bu asla gerçekleşmemelidir.