
أود اليوم أن أحضر قسمًا مشوقًا للغاية ، لكن غالبًا ما يتم تغطيته في أسرار لمبرمجي البشر العاديين في قاعدة البيانات (DB) - مستويات عزل المعاملة. كما تبين الممارسة ، فإن الكثير من الأشخاص المرتبطين بتكنولوجيا المعلومات ، وخاصةً العمل مع قواعد البيانات ، لا يفهمون سبب الحاجة إلى هذه المستويات وكيف يمكن استخدامها لمصلحتهم الخاصة.
قليلا من الناحية النظرية
لا تتطلب المعاملات نفسها تفسيرات خاصة ؛ المعاملة هي استعلامات N (N≥1) لقاعدة البيانات التي سيتم تنفيذها بنجاح جميعًا أو لا على الإطلاق. يُظهر عزل المعاملة مقدار المعاملات الموازية التي تؤثر على بعضها البعض.
عند اختيار مستوى المعاملة ، نحاول التوصل إلى إجماع في الاختيار بين الاتساق العالي للبيانات بين المعاملات وسرعة هذه المعاملات نفسها.
تجدر الإشارة إلى أن أعلى سرعة للتنفيذ وأقل تناسق تتم
قراءتها بدون التزام. أقل سرعة تنفيذ وأعلى تناسق قابل
للتسلسل .
إعداد البيئة
على سبيل المثال ، تم اختيار MySQL DBMS. يمكن أيضًا استخدام PostgreSQL ، لكنه لا يدعم مستوى العزل
غير الملتزم به للقراءة ،
ويستخدم مستوى
الالتزام بالقراءة بدلاً من ذلك . وكما اتضح فيما بعد ، فإن قواعد إدارة قواعد البيانات (DBMS) المختلفة تتصور مستويات العزل بشكل مختلف. يمكن أن يكون لديهم فروق دقيقة مختلفة في ضمان العزلة أو الحصول على مستويات إضافية أو عدم وجود معرفة جيدة.
قم بإنشاء بيئة باستخدام صورة MySQL النهائية باستخدام Docker Hub. وملء قاعدة البيانات.
عامل ميناء-compose.yamlversion: '3.4' services: db: image: mysql:8 environment: - MYSQL_ROOT_PASSWORD=12345 command: --init-file /init.sql volumes: - data:/var/lib/mysql - ./init.sql:/init.sql expose: - "3306" ports: - "3309:3306" volumes: data:
نشر قاعدة البيانات create database if not exists bank; use bank; create table if not exists accounts ( id int unsigned auto_increment primary key, login varchar(255) not null, balance bigint default 0 not null, created_at timestamp default now() ) collate=utf8mb4_unicode_ci; insert into accounts (login, balance) values ('petya', 1000); insert into accounts (login, balance) values ('vasya', 2000); insert into accounts (login, balance) values ('mark', 500);
دعنا نفكر في كيفية عمل المستويات وميزاتها.
سنقوم بتنفيذ أمثلة على معاملات منفذة في وقت واحد. بشروط ، سيتم تسمية المعاملة في النافذة اليسرى
بالمعاملة 1 (T1) ، في الإطار الأيمن -
المعاملة 2 (T2).
قراءة غير ملتزم بها
المستوى مع أسوأ اتساق البيانات ، ولكن أعلى سرعة المعاملات. يتحدث اسم المستوى عن نفسه - كل معاملة ترى تغييرات غير ملتزم بها في معاملة أخرى (ظاهرة
القراءة القذرة ). دعونا نرى كيف تؤثر هذه المعاملات على بعضها البعض.
الخطوة 1. نبدأ 2 المعاملات الموازية.
الخطوة 2. ننظر إلى المعلومات التي لدينا في البداية.
الخطوة 3. الآن نقوم بتنفيذ عمليات INSERT ، DELETE ، UPDATE في T1 ، ونرى ما تراه الصفقة الأخرى الآن.

ترى T2 بيانات من معاملة أخرى لم يتم الالتزام بها بعد.
الخطوة 4. و T2 يمكن الحصول على بعض البيانات.
الخطوة 5. عند استرجاع التغييرات إلى T1 ، ستكون البيانات التي يتلقاها T2 خاطئة.

في هذا المستوى ، من المستحيل استخدام البيانات على أساسها يتم استخلاص القرارات والقرارات المهمة للتطبيق لأن هذه الاستنتاجات يمكن أن تكون بعيدة عن الواقع.
يمكن استخدام هذا المستوى ، على سبيل المثال ، لإجراء الحسابات التقريبية لشيء ما. يمكن استخدام النتيجة
COUNT (*) أو
MAX (*) في بعض التقارير غير الصارمة.
مثال آخر هو وضع التصحيح. عندما تريد أن ترى ما يحدث لقاعدة البيانات أثناء المعاملة.
قراءة ملتزمة
بالنسبة إلى هذا المستوى ، لا ترى المعاملات التي يتم تنفيذها بشكل متزامن إلا التغييرات الملتزم بها من المعاملات الأخرى. وبالتالي ، فإن هذا المستوى يوفر الحماية ضد
القراءة القذرة .
تشبه الخطوة 1 والخطوة 2 المثال السابق.
الخطوة 3. ننفذ أيضًا 3 عمليات بسيطة باستخدام جدول الحسابات (T1) ونقوم باختيار كامل لهذه الجداول في كلتا المعاملتين.

وسوف نرى أن ظاهرة
القراءة القذرة غائبة في T2.
الخطوة 4. نقوم بإصلاح التغييرات في T1 وتحقق مما تراه T2 الآن.

الآن T2 يرى كل ما قام به T1. هذه هي الظاهرة المزعومة المتمثلة في
عدم تكرار القراءة عندما نرى خطوطًا محدثة ومحذوفة (UPDATE ، DELETE) ، وظاهرة
قراءة الأوهام عندما نرى سجلات مضافة (INSERT).
قراءة متكررة
مستوى لمنع ظاهرة
عدم تكرار القراءة . أي لا نرى سجلات تم تغييرها وحذفها في معاملة أخرى مع معاملة أخرى. لكننا لا نزال نرى السجلات المدرجة من معاملة أخرى.
قراءة الوهمية لا تذهب إلى أي مكان.
كرر الخطوة 1 والخطوة 2 مرة أخرى.
الخطوة 3. في T1 ، نقوم بتنفيذ استعلامات INSERT و UPDATE و DELETE. بعد ذلك ، في T2 ، نحاول تحديث نفس السطر الذي تم تحديثه في T1.

ونحصل على القفل: سينتظر T2 حتى يقوم T1 بالتغييرات أو التراجع.
الخطوة 4. إصلاح التغييرات التي أجراها T1. وقراءة البيانات مرة أخرى من جدول الحسابات في T2.

كما ترون ، لا
يتم ملاحظة ظاهرة
عدم تكرار القراءة وقراءة الأشباح . كيف يمكن أن تسمح لنا
القراءة المتكررة بشكل افتراضي بمنع ظاهرة
القراءة غير المتكررة فقط ؟
في الواقع ، يفتقر MySQL إلى تأثير
قراءة الأشباح لمستوى
القراءة القابل للتكرار . وفي PostgreSQL ، تخلصوا منه أيضًا لهذا المستوى. رغم أنه في التمثيل الكلاسيكي لهذا المستوى ، يجب أن نلاحظ هذا التأثير.
مثال مجردة صغير هو خدمة توليد شهادات الهدايا (الرموز) واستخدامها. على سبيل المثال ، قام المهاجم بإنشاء رمز شهادة لنفسه ويحاول تنشيطه ، في محاولة لإرسال عدة طلبات متتالية لتنشيط قسيمة. في هذه الحالة ، سنبدأ العديد من المعاملات التي يتم تنفيذها بشكل متزامن مع نفس القسيمة. وفي بعض الحالات ، قد يحدث تنشيط مزدوج أو حتى ثلاثي القسيمة (سيتلقى المستخدم مكافآت 2x / 3x). في حالة
تكرار القراءة ، في هذه الحالة ، سيحدث قفل وسيحدث التنشيط مرة واحدة ، وفي المستويين السابقين ، يكون التنشيط المتعدد ممكنًا. يمكن أيضًا حل مشكلة مماثلة باستخدام استعلام
SELECT FOR UPDATE ، والذي سيمنع أيضًا السجل المحدّث (كوبون).
تسلسل
المستوى الذي تتصرف به المعاملات كما لو أنه لا يوجد شيء آخر ، لا يوجد أي تأثير على بعضها البعض. في التمثيل الكلاسيكي ، هذا المستوى يلغي تأثير
قراءة الأوهام .
الخطوة 1. بدء المعاملة.
الخطوة 2. T2 نقرأ جدول الحسابات ، ثم T1 نحاول تحديث البيانات التي قرأتها T2.

نحصل على القفل: لا يمكننا تغيير البيانات في معاملة واحدة تتم قراءتها في معاملة أخرى.
الخطوة 3. كل من INSERT و DELETE يقودنا إلى القفل في T1.

حتى تكمل T2 عملها ، لن نتمكن من التعامل مع البيانات التي قرأتها. نحصل على أقصى اتساق البيانات ، لن يتم تسجيل أي بيانات إضافية. ثمن هذا هو بطء سرعة المعاملات بسبب الأقفال المتكررة ، لذلك مع بنية التطبيق الضعيفة يمكن أن يلعب هذا خدعة عليك.
النتائج
في معظم التطبيقات ، نادراً ما يتغير مستوى العزل ويتم استخدام القيمة الافتراضية (على سبيل المثال ، في MySQL
يمكن تكرار القراءة ، في PostgreSQL ، يتم
قراءة الالتزام به ).
ولكن بشكل دوري توجد مشاكل يمكن أن يساعد إيجاد توازن أفضل بين تناسق البيانات العالية أو سرعة المعاملة في حل بعض مشكلات التطبيق.