التزامن والسباقات
Concurrency and Races
التزامن والسباقات — Concurrency and Races
Race condition تحدث عندما يقرأ طلبان نفس البيانات ثم يكتبان بناءً على قراءة قديمة. مثال: المخزون 1. طلبان يقرآن 1 في الوقت نفسه، كلاهما يظن أن الشراء ممكن، ثم كلاهما يخفض المخزون. النتيجة مخزون سلبي أو بيع زائد.
الحل ليس “نأمل أن لا يحدث”. استخدم معاملات، شروط تحديث ذرية، وقيود. مثال: UPDATE products SET stock = stock - 1 WHERE id = ? AND stock > 0. ثم افحص عدد الصفوف المتأثرة. إذا كان صفاً واحداً، نجح الحجز. إذا صفر، لا يوجد مخزون كافٍ.
مثال نمط آمن
الشرط stock > 0 جزء من التحديث نفسه، وليس فحصاً منفصلاً فقط.
SQLite لا يعرف Deadlock
Deadlock يحدث حين يحمل طلبان قفلين ويحاول كل منهما الحصول على قفل الآخر — دائرة انتظار مستحيلة. MySQL وPostgreSQL يكتشفان هذا ويتراجعان تلقائياً.
في SQLite هذا مستحيل لسبب بنيوي: يوجد كاتب واحد فقط في أي وقت. لا توجد دائرة انتظار لأن القفل واحد، والطلب الثاني إما ينتظر أو يستلم SQLITE_BUSY.
-- ضبط مهلة الانتظار قبل إرجاع SQLITE_BUSY
PRAGMA busy_timeout = 5000; -- انتظر حتى 5 ثوانٍ ثم أعِد الخطأ
في التطبيق، تعامل مع SQLITE_BUSY بمنطق إعادة المحاولة (retry) بعد فاصل قصير. هذا أبسط بكثير من معالجة deadlocks.
| الحالة | SQLite | PostgreSQL / MySQL |
|---|---|---|
| طلبان يكتبان في نفس الوقت | SQLITE_BUSY — أحدهما ينتظر | Lock contention أو Deadlock محتمل |
| Deadlock ممكن؟ | لا | نعم |
| الحل | busy_timeout + retry | Deadlock detection + rollback تلقائي |