في هذا الدرس 6تصفّح المواضيع
عندما تتعامل مئات الجلسات المتزامنة مع نفس الجداول قراءةً وكتابةً، يحدد معيار SQL القياسي ثلاث ظواهر تزامن (Read Phenomena) صُممت مستويات العزل لمنعها:
- القراءة المتسخة (
Dirty Read): أن تقرأ الجلسة (أ) بيانات عدلتها الجلسة (ب) قبل اعتمادها؛ فإذا نفذت الجلسة (ب) أمرROLLBACKلاحقاً، تكون الجلسة (أ) قد بنت قرارها على بيانات وهمية. - القراءة غير القابلة للتكرار (
Non-Repeatable Read): أن تقرأ الجلسة (أ) نفس الصف مرتين داخل معاملة واحدة فتجد قيمته قد تغيرت لأن الجلسة (ب) اعتمدت أمرUPDATEبين القراءتين. - القراءة الشبحية (
Phantom Read): أن تنفذ الجلسة (أ) استعلام نطاق شرطي مرتين فتظهر صفوف جديدة لم تكن موجودة لأن الجلسة (ب) اعتمدت أمرINSERTضمن ذلك النطاق. SELECT @@transaction_isolation: يستعلم عن مستوى العزل النشط في الجلسة والخادم (REPEATABLE-READافتراضياً في MySQL 8).
+-------------------+-------------------+
| session_isolation | global_isolation |
+-------------------+-------------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-------------------+-------------------+SELECT @@transaction_isolation AS session_isolation,
@@global.transaction_isolation AS global_isolation;
START TRANSACTION;
SELECT account_id, balance FROM wallet_ledgers WHERE account_id = 101;
COMMIT;
يتيح لك محرك InnoDB ضبط مستوى العزل للجلسة الحالية عبر الأمر SET SESSION TRANSACTION ISOLATION LEVEL بين أربعة مستويات قياسية مرتبة من الأقل عزلاً إلى الأعلى صرامةً:
READ UNCOMMITTED: يسمح بالقراءة المتسخة وغير المتكررة والشبحية؛ نادراً ما يُستخدم في الإنتاج لخطورة قراءة بيانات غير معتمدة.READ COMMITTED: يمنع القراءة المتسخة تماماً، وينشئ لقطة قراءة جديدة مع كل جملةSELECTمنفردة داخل المعاملة بحيث ترى أحدث البيانات المعتمدة.REPEATABLE READ(المستوى الافتراضي في InnoDB): يثبت لقطة قراءة موحدة طوال المعاملة منذ أول عملية قراءة، فيمنع القراءة المتسخة وغير المتكررة والشبحية معاً.SERIALIZABLE: أعلى درجات العزل؛ يحوّل جملSELECTالعادية إلى قراءات مقفلة (FOR SHARE) لمنع أي تعديل متزامن، لكنه يقلل سرعة التزامن.
+------------------+
| active_isolation |
+------------------+
| READ-COMMITTED |
+------------------+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT @@transaction_isolation AS active_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
محاكي مستويات العزل وأقفال الصفوف في InnoDB
كيف يستطيع آلاف الزوار تنفيذ استعلامات SELECT في نفس اللحظة التي تجري فيها معاملات UPDATE دون أن يعطل أحدهما الآخر؟ السر يكمن في تقنية التحكم بالتزامن متعدد النسخ (MVCC)؛ إذ يحتفظ محرك InnoDB داخل كل صف بمعرّف المعاملة التي عدلته (DB_TRX_ID) ومؤشر (DB_ROLL_PTR) يشير إلى النسخ التاريخية السابقة للصف في سجل التراجع:
- القراءة المتسقة غير الحاجزة: لا تضع جمل
SELECTالعادية أي أقفال على الصفوف؛ بل تقارن معرّف معاملة الصف بلقطة القراءة (Read View) الخاصة بجلستك. - استرجاع النسخة التاريخية من Undo Log: إذا كان الصف قد عُدِّل بواسطة معاملة أحدث من لقطتك، يتتبع المحرك مؤشر التراجع لإرجاع النسخة المتسقة كما كانت وقت بدء قراءتك.
START TRANSACTION WITH CONSISTENT SNAPSHOT;: ينشئ لقطة القراءة المتسقة منذ اللحظة الأولى لفتح المعاملة دون انتظار أول جملةSELECT.- القارئ لا يعطل الكاتب: بفضل
MVCC، تعمل القراءات العادية بأقصى سرعة دون إيقاف عمليات الكتابة المتزامنة.
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT account_id, holder, balance
FROM wallet_ledgers
WHERE account_id IN (101, 102);
COMMIT;
رغم روعة القراءة غير الحاجزة في التقارير، فإن الاعتماد على جملة SELECT عادية قبل تعديل رصيد أو حجز مقعد طيران يؤدي إلى ثغرة تضارب شهيرة تُعرف باسم ضياع التحديث (Lost Update)؛ إذ تقرأ جلستان في نفس اللحظة أن المقعد متاح (is_booked = 0) فتحجزانه معاً لمستخدمين مختلفين! لمنع هذا التضارب، نستخدم القراءة القافلة للصفوف:
SELECT ... FOR UPDATE;: يفرض قفلاً حصرياً (Exclusive X Lock) على الصفوف المطابقة؛ فلا تستطيع أي معاملة أخرى تعديل الصف رقم14أو قفله حتى تعتمد معاملتك الحالية أو تتراجع عنها.SELECT ... FOR SHARE;: يفرض قفلاً مشتركاً (Shared S Lock) في MySQL 8، فيسمح للجلسات الأخرى بقراءة الصف ولكنه يمنع أي جلسة من تعديله أو حذفه.- أهمية الفهرس في قفل الصفوف: يضع محرك
InnoDBالأقفال على سجلات الفهرس (Index Records)؛ لذا احرص دائماً على أن يعتمد شرطWHEREمعFOR UPDATEعلى عمود مفهرس، لأن غياب الفهرس يضطر المحرك لقفل جميع صفوف الجدول أثناء المسح الكامل.
+---------+-------------+-----------+
| seat_id | flight_code | is_booked |
+---------+-------------+-----------+
| 14 | RJ-402 | 0 |
+---------+-------------+-----------+START TRANSACTION;
SELECT seat_id, flight_code, is_booked
FROM flight_seats
WHERE seat_id = 14 AND is_booked = 0
FOR UPDATE;
UPDATE flight_seats SET is_booked = 1 WHERE seat_id = 14;
COMMIT;
عندما تقفل الجلسة الأولى الصف (أ) وتنتظر الصف (ب)، بينما تقفل الجلسة الثانية الصف (ب) وتنتظر الصف (أ)، تنشأ حلقة انتظار دائرية تُسمى الإقفال المتبادل (Deadlock). كما أن انتظار تحرير القفل لمدة 50 ثانية افتراضياً (innodb_lock_wait_timeout) يعطل طوابير المهام السريعة. يوفر MySQL 8 حلولاً هندسية حاسمة:
- الكشف التلقائي عن الإقفال المتبادل: يكتشف محرك
InnoDBحلقة الانتظار الدائرية فوراً ويتراجع عن المعاملة الأصغر حجماً مع إرجاع الخطأERROR 1213 (40001): Deadlock foundلتتمكن من إعادة محاولتها برمجياً. - الوقاية من Deadlock: رتّب دائماً تعديل وقفل الصفوف بترتيب تصاعدي ثابت للمفتاح الأساسي (
ORDER BY id ASC) في جميع المعاملات. FOR UPDATE NOWAIT: يرفض الانتظار تماماً ويُرجع خطأ فورياً (ERROR 3572) إذا كان الصف مقفلاً من جلسة أخرى.FOR UPDATE SKIP LOCKED: يتخطى أي صفوف مقفلة حالياً ويقفل أول صف متاح غير مقفل، وهو الحل المثالي لبناء طوابير معالجة المهام (Job Queues) المتوازية في MySQL 8.
START TRANSACTION;
SELECT job_id, payload, status
FROM job_queue
WHERE status = 'pending'
ORDER BY job_id ASC
LIMIT 1
FOR UPDATE SKIP LOCKED;
COMMIT;
تقارن المصفوفة التالية بين مستويات العزل الأربعة في محرك InnoDB داخل MySQL 8:
| مستوى العزل | القراءة المتسخة | القراءة غير المتكررة | القراءة الشبحية (في InnoDB) | نطاق لقطة MVCC |
|---|---|---|---|---|
READ UNCOMMITTED | ممكنة | ممكنة | ممكنة | لا يوجد (يقرأ البيانات غير المعتمدة) |
READ COMMITTED | ممنوعة | ممكنة | ممكنة | لقطة جديدة لكل جملة SELECT |
REPEATABLE READ (الافتراضي) | ممنوعة | ممنوعة | ممنوعة (بأقفال Next-Key) | لقطة موحدة طوال المعاملة |
SERIALIZABLE | ممنوعة | ممنوعة | ممنوعة | يحوّل القراءات إلى أقفال FOR SHARE |
ملخص الدرس: تعلمت في هذا الدرس ظواهر القراءة المتزامنة الثلاث، ومستويات العزل الأربعة في محرك InnoDB، وآلية عمل القراءة المتسقة عبر MVCC، وكيفية قفل الصفوف بأوامر FOR UPDATE وNOWAIT وSKIP LOCKED.
الخطوة التالية والدرس القادم: انتقل إلى الوحدة السابعة عشرة «إدارة الخادم» بدءاً من درس «إدارة حسابات المستخدمين والمصادقة في MySQL».
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
يجمع المستوى الافتراضي REPEATABLE READ في محرك InnoDB بين لقطات MVCC وأقفال الصفوف الدقيقة FOR UPDATE وSKIP LOCKED لتحقيق أعلى درجات الأمان والتزامن. الخطوة التالية: انتقل الآن إلى درس «إدارة حسابات المستخدمين والمصادقة في MySQL».
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Isolation Levels مستويات العزل
- تعلّم مستويات عزل المعاملات وأقفال الصفوف في MySQL بأسلوب MySQL 8 الحديث مع أمثلة استعلامات SQL وتطبيقات تفاعلية.
- للمراجعة
- 02 Concurrency Read Phenomena Explained ظواهر القراءة المتوازية الثلاث
- المفهوم الهندسي الأساسي والصياغة التطبيقية لقسم ظواهر القراءة المتوازية الثلاث في خادم MySQL 8.4.
- للمراجعة
- 03 Four Isolation Levels in InnoDB مستويات العزل الأربعة بالمحرك
- المفهوم الهندسي الأساسي والصياغة التطبيقية لقسم مستويات العزل الأربعة بالمحرك في خادم MySQL 8.4.
- للمراجعة
- 04 Multi Version Concurrency MVCC القراءة المتسقة عبر MVCC
- المفهوم الهندسي الأساسي والصياغة التطبيقية لقسم القراءة المتسقة عبر MVCC في خادم MySQL 8.4.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 MVCC MVCC
- Multi-Version Concurrency Control
- آلية التحكم بالتزامن متعدد النسخ في InnoDB التي تحتفظ بالنسخ السابقة للصفوف في سجل التراجع لتوفير قراءة متسقة غير حاجزة.
- للمراجعة
- 02 X Lock X Lock
- Exclusive Row Lock
- قفل الصف الحصري الذي يُحجز عبر FOR UPDATE أو UPDATE ويمنع الجلسات الأخرى من تعديل الصف أو قفله.
- للمراجعة
- 03 S Lock S Lock
- Shared Row Lock
- قفل الصف المشترك الذي يُحجز عبر FOR SHARE ويسمح بالقراءة المشتركة مع منع تعديل الصف حتى انتهاء المعاملة.
- للمراجعة
- 04 TRX TRX
- Database Transaction Identifier
- معرّف المعاملة الداخلي في محرك InnoDB الذي يُختم على كل صف لتحديد مدى رؤيته في لقطات MVCC.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
نفّذ جمل SQL الواردة في قسم ظواهر القراءة المتوازية الثلاث داخل بيئة MySQL 8 المحلية وتحقق من المخرجات.
-
جرّب الحالات الثلاث داخل محاكي مستويات العزل وأقفال الصفوف في InnoDB في قسم مستويات العزل الأربعة بالمحرك وقارن سلوك المحرك.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي6 أسئلة تنتظرك +
ما مستوى عزل المعاملات الافتراضي في محرك التخزين InnoDB داخل خادم MySQL 8؟
المستوى الافتراضي لعزل المعاملات في محرك InnoDB هو REPEATABLE READ.
بفضل تقنية MVCC في محرك InnoDB، لا تعطل جمل القراءة العادية (SELECT) عمليات التحديث المتزامنة (UPDATE) على نفس الصفوف.
صواب؛ تقرأ جمل SELECT العادية من لقطة MVCC عبر سجل التراجع دون وضع أقفال تعطل الكاتبين.
أي ظاهرة تزامن تحدث عندما تقرأ الجلسة (أ) تعديلات غير معتمدة من الجلسة (ب) ثم تتراجع الجلسة (ب) عنها لاحقاً؟
قراءة بيانات غير معتمدة من جلسة أخرى تُسمى القراءة المتسخة (Dirty Read).
أي عبارة تُضاف لنهاية استعلام SELECT لحجز قفل حصري (X Lock) على الصفوف المستهدفة ومنع حجزها المزدوج؟
تضع العبارة FOR UPDATE قفلاً حصرياً على الصفوف المطابقة حتى انتهاء المعاملة.
أي خيار في MySQL 8 يسمح لعامل طابور المهام بتجاوز الصفوف المقفلة حالياً وقفل المهمة المتاحة التالية فوراً دون انتظار؟
يتجاوز الخيار FOR UPDATE SKIP LOCKED الصفوف المحتجزة ويسحب أول صف متاح غير مقفل فوراً.
عندما يكتشف محرك InnoDB إقفالاً متبادلاً (Deadlock) بين معاملتين، فإنه يتراجع تلقائياً عن إحداهما ويُرجع الخطأ رقم 1213.
صواب؛ يفك محرك InnoDB حلقة الانتظار الدائرية تلقائياً بالتراجع عن إحدى المعاملتين وإرجاع الخطأ 1213.