القراءات المتسخة وغير القابلة للتكرار والوهمية
الأنواع الثلاثة لشذوذ القراءة ومستوى العزل الذي يمنع كلًا منها
القراءات المتسخة وغير القابلة للتكرار والوهمية درس مجاني في Coding Interview Prep على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Coding Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.
حالات شذوذ القراءة الثلاث
توجد مستويات العزل لمنع أخطاء تزامن محددة تُسمى حالات شذوذ القراءة. ويتوقع منك المحاورون تعريف الحالات الثلاث بدقة وربط كل منها بالمستوى الذي يمنعها.
- القراءة المتسخة - قراءة بيانات لم تُثبت بعد
- القراءة غير القابلة للتكرار - تغيّر صف بين عمليتي قراءة
- القراءة الوهمية - ظهور صفوف جديدة بين عمليتي قراءة
يكمن التحدي في التمييز بين القراءة غير القابلة للتكرار والقراءة الوهمية، لأن كلتيهما تتضمنان إعادة الاستعلام والحصول على نتائج مختلفة.
تعريف القراءة المتسخة
تحدث القراءة المتسخة عندما تقرأ المعاملة T1 صفًا عدّلته المعاملة T2 لكنه لم يُثبت بعد. فإذا نفذت T2 عملية التراجع، تكون T1 قد اتخذت إجراءً استنادًا إلى بيانات لم تكن موجودة فعليًا قط.
لا يسمح بالقراءات المتسخة سوى READ UNCOMMITTED. أما جميع المستويات الأعلى فتمنعها.
الخطر في العالم الواقعي: الموافقة على قرض استنادًا إلى إيداع يُلغى بعد ذلك بثوانٍ.
مخطط زمني للقراءة المتسخة
اقرأ العمودين باعتبارهما مخططًا زمنيًا. تعمل T1 عند مستوى READ UNCOMMITTED.
ترى T1 رصيدًا قدره 700، لكن T2 لا تنفذ عملية التثبيت قط. كانت قيمة 700 وهمًا ناتجًا عن عمل T2 الجاري. بعد تراجع T2، تظل القيمة الحقيقية 500. وقد اتخذت T1 قرارًا استنادًا إلى بيانات لا قيمة لها.
-- T2 (not committed) | -- T1 (READ UNCOMMITTED)
BEGIN; |
UPDATE accounts |
SET balance = 700 |
WHERE id = 1; |
| SELECT balance FROM accounts
| WHERE id = 1; -- reads 700 (dirty!)
ROLLBACK; |
| -- T1 acted on a value that never existedتعريف القراءة غير القابلة للتكرار
تحدث القراءة غير القابلة للتكرار عندما تقرأ T1 صفًا، ثم تنفذ T2 عملية تثبيت لتحديث ذلك الصف نفسه أو حذفه، ثم تقرأه T1 مرة أخرى فترى قيمة مختلفة.
لاحظ الفرق الأساسي عن القراءة المتسخة: فقد نفذت T2 هنا عملية التثبيت. البيانات حقيقية، لكنها تغيرت أثناء تنفيذ T1 ضمن معاملة واحدة.
لا يزال READ COMMITTED يسمح بذلك. أما REPEATABLE READ والمستويات الأعلى فتمنعه من خلال القراءة من لقطة ثابتة.
مخطط زمني للقراءة غير القابلة للتكرار
تعمل T1 عند مستوى READ COMMITTED وتقرأ الصف نفسه مرتين. وبين عمليتي القراءة، تثبت T2 تغييرًا.
يعيد المفتاح الأساسي نفسه قيمتين مختلفتين داخل معاملة واحدة. وقد يؤدي هذا التناقض إلى تعطل المنطق متعدد الخطوات الذي يفترض ثبات الصف.
-- T1 (READ COMMITTED) | -- T2
BEGIN; |
SELECT balance FROM accounts |
WHERE id = 1; -- 500 |
| BEGIN;
| UPDATE accounts SET balance = 900
| WHERE id = 1;
| COMMIT;
SELECT balance FROM accounts |
WHERE id = 1; -- 900 (changed!) |
COMMIT; |تعريف القراءة الوهمية
تحدث القراءة الوهمية عندما تنفذ T1 استعلامًا يتضمن شرط بحث، ثم تثبت T2 عملية INSERT (أو DELETE) لصفوف تطابق ذلك الشرط، ثم تعيد T1 تنفيذ الاستعلام فترى مجموعة صفوف مختلفة.
يكمن الفرق عن القراءة غير القابلة للتكرار في أن القراءة غير القابلة للتكرار تتعلق بتغير قيمة صف موجود، بينما تتعلق القراءة الوهمية بتغير عدد الصفوف المطابقة لشرط التصفية.
يضمن المعيار أن SERIALIZABLE وحده يمنع القراءات الوهمية.
مخطط زمني للقراءة الوهمية
تحسب T1 عدد الحسابات ذات القيم المرتفعة مرتين. وبين عمليتي العد، تُدخل T2 صفًا جديدًا مطابقًا للشرط وتثبت المعاملة.
لم يتغير أي صف موجود، ومع ذلك اختلفت نتيجة COUNT. الصف الجديد هو «الوهم» الذي ظهر في مجموعة النتائج الخاصة بـ T1.
-- T1 (REPEATABLE READ, standard) | -- T2
BEGIN; |
SELECT COUNT(*) FROM accounts |
WHERE balance > 1000; -- 3 |
| INSERT INTO accounts(id, balance)
| VALUES (99, 5000);
| COMMIT;
SELECT COUNT(*) FROM accounts |
WHERE balance > 1000; -- 4 (phantom)|
COMMIT; |ربط حالات الشذوذ بمستويات العزل
هذا الربط هو جوهر الموضوع. المستوى الأدنى الذي يمنع كل حالة شذوذ هو:
- تُمنع القراءة المتسخة ابتداءً من
READ COMMITTED. - تُمنع القراءة غير القابلة للتكرار ابتداءً من
REPEATABLE READ. - تُمنع القراءة الوهمية عند
SERIALIZABLE، وفقًا للمعيار.
لاحظ أن الأسماء متوافقة مع الوظيفة: يجعل REPEATABLE READ القراءات قابلة للتكرار، وقد سُمّيت المستويات نسبةً إلى حالة الشذوذ التي تعالجها حديثًا.
الفرق الدقيق بين القراءة غير القابلة للتكرار والقراءة الوهمية
هذا هو الالتباس الأكثر شيوعًا في المقابلات. تذكّر هذه الجملة:
القراءة غير القابلة للتكرار = تغيّر قيمة صف موجود. القراءة الوهمية = تغيّر مجموعة الصفوف المطابقة (بإضافة صفوف أو إزالتها).
اختبر نفسك: تنفذ T2 UPDATE ... WHERE id = 5 ثم تثبت المعاملة، وتعيد T1 قراءة الصف 5. هذه قراءة غير قابلة للتكرار. أما إذا نفذت T2 عملية INSERT لصف جديد يطابق شرط WHERE الخاص بـ T1، ثم أعادت T1 تنفيذ الاستعلام، فهذه قراءة وهمية.
انحراف الكتابة: حالة الشذوذ الإضافية
قد تتجاوز المقابلات المتقدمة حالات الشذوذ الثلاث القياسية لتتناول انحراف الكتابة: تقرأ معاملتان كل منهما مجموعة متداخلة، ثم تنفذان عمليات كتابة غير متداخلة استنادًا إلى ما قرأتاه، وتثبتان معًا، فتتركان حالة لم تكن أي منهما لتسمح بها منفردة.
مثال كلاسيكي: طبيبان مناوبان؛ يتحقق كل منهما من أن طبيبًا آخر مناوب، ثم يلغي مناوبته. ينجح كلاهما، فلا يبقى أي طبيب للتغطية.
يسمح عزل اللقطات (REPEATABLE READ في Postgres) بانحراف الكتابة؛ ولا يمنعه سوى SERIALIZABLE. وذكر هذه النقطة يدل على عمق فهمك.
التحديث المفقود: الفخ الرابع
يُدخل المحاورون أحيانًا التحديث المفقود، وهو ليس ضمن قائمة حالات الشذوذ في المعيار، لكنه يتكرر كثيرًا في الممارسة. تقرأ معاملتان القيمة نفسها، وتحسب كل منهما قيمة جديدة انطلاقًا منها، ثم تكتبان النتيجة. فتستبدل الكتابة الثانية الأولى بصمت.
مثال: تقرأ معاملتا تحويل الرصيدَين 500، وتطرح كل منهما مبلغًا، ثم تكتب كل منهما نتيجتها. فتُفقد إحدى عمليتي الطرح.
لا يكمن الحل في رفع مستوى العزل فحسب، بل في استخدام قفل صريح عبر SELECT ... FOR UPDATE، أو تحديث ذري يحسب القيمة داخل قاعدة البيانات بدلًا من التطبيق.
-- Safe pattern: lock the row, or compute atomically
BEGIN;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; -- locks row
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
-- Or simply: UPDATE accounts SET balance = balance - 100 WHERE id = 1;تحقق سريع
حدّد حالة الشذوذ من سلوكها.
مراجعة: حالات الشذوذ وحلولها
ثلاث حالات شذوذ للقراءة، تعالج كل منها بزيادة مستوى العزل:
- القراءة المتسخة (بيانات لم تُثبت بعد) - تُعالج عند READ COMMITTED.
- القراءة غير القابلة للتكرار (تغيّر قيمة صف موجود) - تُعالج عند REPEATABLE READ.
- القراءة الوهمية (تغيّر مجموعة الصفوف المطابقة) - تُعالج عند SERIALIZABLE.
احرص على التمييز الدقيق بين القراءة غير القابلة للتكرار والقراءة الوهمية، واذكر انحراف الكتابة إذا أراد المحاور مزيدًا من التفاصيل. سننظر بعد ذلك في كيفية تطبيق المحركات للعزل فعليًا: الأقفال، وحالات الجمود، وMVCC.
الأسئلة الشائعة
هل درس «القراءات المتسخة وغير القابلة للتكرار والوهمية» مجاني؟
نعم — نص درس «القراءات المتسخة وغير القابلة للتكرار والوهمية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Coding Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.
ماذا ستتعلم في «القراءات المتسخة وغير القابلة للتكرار والوهمية»؟
الأنواع الثلاثة لشذوذ القراءة ومستوى العزل الذي يمنع كلًا منها تتمرن على Coding Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Coding Interview Prep؟
لا تُشترط خبرة سابقة. Coding Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «القراءات المتسخة وغير القابلة للتكرار والوهمية»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Coding Interview Prep هذا؟
نعم. كل درس في Coding Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- شرح خصائص ACID
- مستويات العزل الأربعة
- القراءات المتسخة وغير القابلة للتكرار والوهمية
- حالات التعارض والأقفال وMVCC