Lost update — ikki concurrent amal bir qiymatning eski holatini o‘qib, alohida yangi qiymat yozganda keyingi yozuv avvalgisini sezmasdan almashtirib yuboradigan anomaly. Natijada transactionlardan biri muvaffaqiyatli ko‘ringan bo‘lsa-da, uning o‘zgarishi yakuniy holatda yo‘qoladi.
Read-modify-write sikli
Hisoblagich 10 bo‘lsin. A va B bir vaqtda uni o‘qiydi. Har ikkisi 10 + 1 = 11 hisoblaydi va 11 yozadi. Ikki incrementdan keyin kutilgan qiymat 12, amaldagi qiymat 11 bo‘ladi.
Muammo bitta HTTP request yoki kod satrida ko‘rinmasligi mumkin:
value = SELECT counter FROM stats;
UPDATE stats SET counter = value + 1;
SELECT va UPDATE orasida boshqa transaction qiymatni o‘zgartiradi.
Atomic update
Oddiy arithmetic o‘zgarish database ichida bitta statement bilan bajariladi:
UPDATE stats
SET counter = counter + 1
WHERE id = 42;
Row lock va engine concurrency nazorati har update’ni amaldagi qiymatga qo‘llaydi. Bu alohida read-modify-write’dan xavfsizroq. Murakkab biznes mantiqida esa oldingi holatni tekshirish talab qilinadi.
Pessimistic locking
SELECT ... FOR UPDATE rowni o‘qish paytida lock qiladi. Boshqa writer birinchi transaction tugaguncha kutadi. Transaction qisqa bo‘lishi, locklar bir xil tartibda olinishi va user input kutmasligi kerak. Aks holda contention va deadlock oshadi.
Lock faqat ayni database transaction doirasida himoya qiladi. Qiymatni o‘qib transactionni yopib, keyin boshqa requestda yozish lockni saqlamaydi.
Optimistic concurrency
Version yoki oldingi qiymat WHERE shartiga qo‘shiladi:
UPDATE documents
SET content = :new_content, version = version + 1
WHERE id = :id AND version = :old_version;
Affected row 0 bo‘lsa boshqa writer oldin o‘zgartirgan. Application conflict ko‘rsatadi, qayta o‘qiydi yoki xavfsiz merge qiladi. HTTP API’da ETag va If-Match shu modelga o‘xshaydi.
Isolation darajasi
Database engine va isolation darajasi ayrim lost update’larni avtomatik abort qilishi mumkin. Biroq barcha read-modify-write shakli va ORM xulqi bir xil emas. Snapshot yoki repeatable read borligi yetarli deb taxmin qilinmaydi; real concurrent test bajariladi.
Serializable isolation ketma-ket bajarilishga mos natijani maqsad qiladi, ammo transaction serialization failure olib retry talab qilishi mumkin. Retry tashqi side effectni takrorlamasligi uchun idempotency kerak.
Qayerda uchraydi
Profile editda ikki browser tab turli maydonni o‘zgartirsa, ORM butun rowni eski qiymatlar bilan saqlab boshqasining maydonini yo‘qotishi mumkin. Faqat o‘zgargan ustunlarni update qilish xavfni kamaytiradi, lekin ayni ustun conflictini hal qilmaydi.
Inventory, balance va quota’da lost update to‘g‘ridan-to‘g‘ri moliyaviy xato beradi. Constraint qiymat manfiy bo‘lmasligini tekshirishi mumkin, ammo yo‘qolgan incrementni qaytarmaydi.
Kuzatuv va test
Optimistic conflict rate, retry, deadlock va lock wait kuzatiladi. Version mismatch normal concurrency signali bo‘lishi mumkin, keskin oshishi UX yoki workload muammosini ko‘rsatadi.
Test ikki connectionni bir xil eski qiymatni o‘qishga majbur qiladi, so‘ng yozuvlarni nazoratli tartibda bajaradi. Yakuniy qiymat va affected rows tekshiriladi. Faqat tez parallel loop nondeterministic bo‘lib, anomaly’ni ishonchli takrorlamasligi mumkin.
API darajasida versiya raqami yoki ETag bilan shartli yangilash keng qo‘llanadi. Server mijoz o‘qigan versiya hali joriy ekanini tekshiradi; mos kelmasa, konflikt qaytaradi. Mijoz esa yangi holatni olib, qarorni ongli ravishda takrorlaydi.
Bog‘liq tushunchalar
Concurrency control, MVCC, Optimistic locking, Pessimistic locking, Version column, Atomic update, Write skew, Transaction isolation