مبادئ الـ 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
أتمنى أن تكون قد استفدت من هذه المقالات وأن تكون قد فهمت كل شيء بشكل جيد