انتقال للمقال
وقت القراءة: ≈ 5 دقائق

مبادئ الـ ACID في إدارة الـ Transactions

السلام عليكم ورحمة الله وبركاته

يمكنك متابعة السلسلة بالترتيب أو الانتقال مباشرة إلى أي مقال:


المقدمة

هذه المقالة تعتبر مقدمة لأهم مبادئ قواعد البيانات وهي مبادئ الـ ACID الأربعة
والتي تعتبر من أهم المبادئ التي يجب على كل مطور أن يعرفها ويفهمها جيدًا

وهي كالتالي:

وهذه المبادئ هي التي تقوم عليها فكرة الـ Database Transactions
وهي تساعدنا على تنفيذ العمليات بشكل آمن ومضمون ودقيق

لكن ما هي الـ Transactions ؟
كيف يمكننا أن نشرح ونتعلم مبادئ شئ نحن نجهله من الأساس
لذا قبل أن نبدأ في شرح كل مبدأ على حدة سنتعرف على ما هي الـ Transactions أولًا

ما هي الـ Transactions ؟

الـ Transactions هي مجموعة من العمليات التي تتم بشكل متسلسل ومتتابع
والعمليات نقصد بها أي Query تقوم بتنفيذها على قاعدة البيانات

فمثلًا إذا قمت بإضافة مستخدم جديد إلى قاعدة البيانات ثم قمت بتعديل شيء ما ثم قمت بحذف شيء معين

INSERT INTO users (name, email) VALUES ('Ahmed', 'eltabaraniahmed@gmail');
UPDATE users SET name = 'Mohamed' WHERE id = 1;
DELETE FROM users WHERE id = 2;

كل عملية منفصلة هنا تسمى Query والعمليات الثلاثة مجتمعة نسميها Transaction

إذا نستطيع أن نقول أن الـ Transaction هي مجموعة من الـ Query التي تتم بشكل
متسلسل ومتتابع وغالبًا ما تكون مرتبطة ببعضها البعض وتحتاج لتنفيذها بترتيب معين
ومبادئ الـ ACID هي مبادئ وضعت لجعل الـ Transactions تنفذ بشكل صحيح دون أي مشاكل

كيفية كتابة Transaction

في معظم الـ SQL لكي تضع مجموعة من الـ Query في Transaction تقوم بكتابة
BEGIN ثم تبدأ بكتابة مجموعة الـ Query الخاصة بك ثم تنهي بـ COMMIT
وكلمة COMMIT تعني نهاية الـ Transaction وبالتالي سيتم تطبيق كل الـ Query
التي كتبتها داخل الـ Transaction على قاعدة البيانات

وإذا حدث أي خطأ في أي Query خلال الـ Transaction سيتم إلغاء الـ Transaction بشكل تلقائي
وعملية إلغاء الـ Transaction تعرف بـ ROLLBACK أي تراجع عن كل ما سبق تنفيذه


ليس كل العمليات التي تنفذ بشكل متسلسل ومتتابع تعتبر Transaction
عليك أن تضعها داخل Transaction لكي تكون Transaction وتتمتع بكل خصائص الـ ACID

وكل لغة SQL تقدم لك طريقة لكتابة Transaction وتنفيذها وسنرى هذا تاليًا

مثال عملي على Transaction

لنفترض أن لدينا جدول يسمى Accounts وجدول آخر يسمى Histories
ونريد تنفيذ عملية تحويل مبلغ من حساب إلى حساب آخر على سبيل المثال

ونريد تنفيذ هذه العمليات بدون Transaction لذا يمكننا كتابتها بدون Transaction كالتالي:

UPDATE Accounts SET balance = balance - 100 WHERE user_id = 1;
INSERT INTO Histories (user_id, amount) VALUES (1, -100);

UPDATE Accounts SET balance = balance + 100 WHERE user_id = 2;
INSERT INTO Histories (user_id, amount) VALUES (2, 100);

هكذا تخيل معي أنه تم تنفيذ الـ Query الأولى بنجاح والثانية بنجاح لكن عندما وصلنا للـ Query الثالثة حدث خطأ ما
في هذه الحالة تم سحب المال من المستخدم رقم 1 وتم تسجيل العملية في جدول Histories
ولكن لم يتم إضافة المال للمستخدم رقم 2 وهذه مشكلة كبيرة

لكن لو كنا وضعنا هذه العمليات داخل Transaction فإن النتيجة ستكون مختلفة:

BEGIN;

UPDATE Accounts SET balance = balance - 100 WHERE user_id = 1;
INSERT INTO Histories (user_id, amount) VALUES (1, -100);

UPDATE Accounts SET balance = balance + 100 WHERE user_id = 2;
INSERT INTO Histories (user_id, amount) VALUES (2, 100);

COMMIT;

نفس الكود السابق ولكن هذه المرة قمنا بوضعه داخل Transaction عن طريق كتابة BEGIN و COMMIT
وهذا يعني أنه إذا حدث أي خطأ في أي Query خلال الـ Transaction سيتم التراجع عن كل ما تم تنفيذه
بالتالي لو تم تنفيذ الـ Query الأولى والثانية بنجاح ولكن حدث خطأ في الـ Query الثالثة فسيتم التراجع عن كل شيء تم تنفيذه ولن يتم تطبيق أي شيء على قاعدة البيانات

هذا يعني أنه إذا حدث أي خطأ في أي Query خلال الـ Transaction سيتم التراجع عن كل ما تم تنفيذه ولن يتم تطبيق أي شيء على قاعدة البيانات

لماذا نحتاج مبادئ الـ ACID ؟

الـ Transaction يحقق لك مبادئ الـ ACID لأنه تم بناءه عليها وبالتالي هو يتبع هذه المبادئ بشكل تلقائي
وهذا ما يجعل الـ Transactions تعمل بشكل صحيح وبدون أي مشاكل

لكن يبقى السؤال ما هي مبادئ الـ ACID بالتحديد ؟
أظن أننا قد تكلمنا عن الـ Transactions وكيف هي تحقق بمبادئ الـ ACID ولكن لم نتكلم عن كل مبدأ على حدة

ولا أريدك أن تظن أن الـ Transactions هي مجرد مجموعة من الـ Query لا أكثر ولا أقل
لذا سنتعرف على كل مبدأ على حدة ونتعرف على فائدته وما الذي يقدمه في الـ Transaction وكيف يساعدنا على تفادي المشاكل


حسنًا كما قلنا فإن هناك أربعة مبادئ أساسية للـ Transactions وهي مبادئ الـ ACID
وهذه المبادئ هي التي تجعل الـ Transactions تعمل بشكل صحيح بدون أي مشاكل لذا لكي نفهم الـ Transactions جيدًا علينا أن نتعرف على هذه المبادئ التي بنيت
عليها

  • مبدأ الـ Atomicity يضمن أن الـ Transaction تنفذ بالكامل أو لا تنفذ على الإطلاق
  • مبدأ الـ Consistency يضمن أن البيانات تبقى متناسقة ومتوافقة مع القيود
  • مبدأ الـ Isolation يضمن أن كل Transaction معزولة عن الأخرى
  • مبدأ الـ Durability يضمن أن البيانات المحفوظة لن تُفقد حتى عند الأعطال

ختامًا

في المقالات المرفقة سنشرح مبادئ الـ ACID وكيفية تطبيقها في الـ Database
وكيفية تحقيق كل مبدأ من هذه المبادئ وكيفية تطبيقها عمليًا
بعض المقالات قد تكون طويلة بعض الشيء لكن كنت أريد أن أشرح كل شيء بشكل عملي مع أمثلة واقعية على قدر المستطاع

وحلولها بإستخدام Laravel وبالطبع شرحت باستخدام الـ ORM الذي يقدمه لأنني أردت التركيز على الأمثلة العملية التي ستقابلها في العمل
وأنت في الغالب ستتعامل مع الـ Database عن طريق الـ ORM وليس الـ SQL بشكل مباشر


ملخص المقالات

أولًا تكلمنا عن الـ Transaction وكيف أنها عبارة عن مجموعة من الـ Query التي تعمل معًا وتنفذ معًا
وكيف أنها تحقق لك المباديء الأربعة للـ ACID بما في ذلك Atomicity وConsistency وIsolation وDurability
وتضمن لك أن الـ Transaction ستنفذ بنجاح وستحفظ البيانات بشكل صحيح

ثم انتقلنا لمبدأ الـ Atomicity والذي يمكننا أن نختصره بجملة واحدة وهي أن الـ Transaction يجب أن تنفذ بالكامل أو لا تنفذ على الإطلاق
بالتالي إذا حدث أي خطأ في الـ Transaction فإنه يجب عليك إلغاء كل التعديلات التي تمت وإعادة البيانات إلى حالتها الأولى وكأن شيء لم يحدث
وهو ما يعرف بالـ ROLLBACK

ثم تحدثنا عن مبدأ الـ Consistency وهو مفهوم نظري واسع جدًا والذي يضمن لك أن البيانات ستكون دائمًا في حالة صحيحة ومتسقة
ويضمن أن الـ Transaction تلتزم بالـ Constraints الذي وضعتها على البيانات ولا تخالفها
بالتالي ستحترم على سبيل المثال الـ Foreign Key والـ Unique Key والـ Check والـ Default والـ Not Null وغيرها
ومفهوم الـ Consistency مفهوم واسع ويتطرق للعديد من الأمور سواء على مستوى الأخطاء البشرية أو الأمور التي تحدث في الـ Database Distribution System
وهل هناك تناقضات بين البيانات في الـ Database المختلفة الموزعة في السيرفرات المختلفة

ثم تحدثنا عن مبدأ الـ Isolation وهو مبدأ يحدد لك كيفية تعامل الـ Transaction مع البيانات وكيفية عزل الـ Transaction عن بعضها البعض
والذي يقوم بمنع أي Query أو Transaction أخرى من الوصول إلى البيانات التي تقوم بتعديلها
ويحتوى على عدة مستويات للعزل منها

  • Read Uncommitted: يسمح لأي Transaction بقراءة البيانات حتى لو لم يتم عمل COMMIT للبيانات
  • Read Committed: يمنع أي Transaction من قراءة البيانات حتى يتم عمل COMMIT للبيانات
  • Repeatable Read: يعزل الـ Transaction عن أي تغييرات خارجية تحدث في البيانات
  • Serializable: ينفذ الـ Transaction بشكل تسلسلي ويمنع أي Transaction من التداخل مع الـ Transaction الأخرى
  • Snapshot: يقوم بعمل نسخة زمنية من البيانات ويعمل على قراءة هذه النسخة وليس البيانات الحالية

يوجد مشاكل تحدث في حالة عدم تطبيق مبدأ الـ Isolation مثل

  • Dirty Read: القدرة على قراءة البيانات قبل عمل COMMIT لها
  • Non-Repeatable Read: القدرة على قراءة نفس البيانات مرتين والحصول على نتائج مختلفة
  • Phantom Read: رؤية صفوف جديدة تمت إضافتها من قبل Transaction أخرى
  • Lost Update: فقدان تحديثات تمت من قبل Transaction أخرى

وأيضًا يمكنك تطبيق مبدأ الـ Isolation بعدة طرق منها

  • Pessimistic Lock
    • له نوعان مهمين وهما
      • Exclusive Lock: يمنع أي Transaction أخرى من قراءة أو كتابة البيانات
      • Shared Lock: يسمح للـ Transaction الأخرى بقراءة البيانات ولكن يمنعها من تعديلها
  • Optimistic Lock
    • يقوم على فكرة وجود حقل version أو timestamp لتحقق منه بعد التعديل

ثم أنهينا بمبدأ الـ Durability والذي يضمن لك أن البيانات ستكون موجودة ولن تفقد
حتى في حالة حدوث عطل أو انقطاع مفاجئ في النظام
والذي يمكننا أن نختصره بأنك عندما تقول لي أنك قمت بعمل COMMIT بأنك تضمن لي أن البيانات قد تم حفظها بمعنى أن الرجل يلتزم بكلمته
والمبدأ مثله مثل الـ Consistency يعتبر مبدأ نظري ويخص بناء أنظمة قواعد البيانات مثل MySQL و PostgreSQL وغيرها
ولكن يمكنك تحقيقه بنفسك عن طريق توفير نوع من الـ Backup لقاعدة البيانات الخاصة بك
أو بتصميم الـ Database بشكل جيد وجعل كل Query تكون Optimized وسريعة وأداءها عالي
لتقليل فرص حدوث مشاكل متعلقة بالبطيء أو Query ثقيلة تسبب Timeout أو Deadlock

أتمنى أن تكون قد استفدت من هذه المقالات وأن تكون قد فهمت كل شيء بشكل جيد