مبدأ الـ Consistency
السلام عليكم ورحمة الله وبركاته
يمكنك متابعة السلسلة بالترتيب أو الانتقال مباشرة إلى أي مقال:
المقدمة
مبدأ الـ Consistency هو المبدأ الذي يضمن لك أن الـ Transaction بعد تنفيذها ستجعل البيانات في الـ Database متناسقة
أي البيانات ستحفظ بشكل صحيح وسليم داخل الـ Database ولن يقوم الـ Transaction بافسادها أو التلاعب بها
في الحقيقة مبدأ الـ Consistency يعني الكثير من الأشياء منها أن الـ Transaction يجب أن تحترم القواعد والقيود التي تم وضعها على الـ Database
بمعنى أن أي Constraint سواء كان Primary Key أو Foreign Key أو Unique قيمة Default أو أي قيد آخر يجب أن تحترمه الـ Transaction ولا تخالفه
أنواع التناسق
مبدأ الـ Consistency أيضًا يعني أنه لا يجب أن يكون هناك أي تعارض بين البيانات
فمثلًا لنتخيل أن هناك شخص يدعى Ahmed ولديه id رقم 10
وقام هذا الشخص بشراء منتج يدعى Laptop ولديه id رقم 20
لذا قمنا بتسجيل هذه العملية في جدول يسمى Orders
وقلنا أنه تم شراء المنتج Laptop الـ id صاحب الـ 20 من قبل Ahmed صاحب الـ id رقم 10
Users Table
+----+-------+
| id | name |
+----+-------+
| 10 | Ahmed |
+----+-------+
Products Table
+----+--------+
| id | name |
+----+--------+
| 20 | Laptop |
+----+--------+
Orders Table
+----+---------+------------+------------+------------+
| id | user_id | product_id | sold_at | arrived_at |
+----+---------+------------+------------+------------+
| 30 | 10 | 20 | 2024-11-01 | 2024-11-05 |
+----+---------+------------+------------+------------+
هكذا البيانات تبدو متناسقة وسليمة ولا توجد بها أي تعارض
لكن تخيل لو أن هناك شيء حدث جعل هذه الجداول غير متناسقة
بحيث أنه يتم تسجيل البيانات بشكل خاطئ فمثلًا
نسجل البيانات بشكل خاطئ ونقول أن الـ product_id هو 2 بينما في الحقيقة هو 1
أو ننسبه للـ user_id مختلف أو حتى نكتب تاريخ العملية بشكل خاطئ فنقول أنه تم شراء المنتج في 2024-10-01 بينما في الحقيقة هو في 2024-11-01
أو نقول أنه تم تسليم المنتج في الماضي أي قبل تاريخ الشراء حتى وهذا يعتبر تعارض وخطأ
مثال أخر قد يكون لديك منتجات تم حذفها من قبل المستخدمين ولكن لا تزال موجودة في قاعدة البيانات كـ foreign key
ويتم استخدامها في العمليات والحسابات الأخرى على الرغم من أنها تم حذفها
وهكذا من الأمور التي تجعل البيانات غير متناسقة وغير صحيحة
وهذا ما يحاول مبدأ الـ Consistency أن يحميك منه
هو ضمان أن البيانات والعمليات التي بداخل الـ Transaction سيتم تنفيذها وتخزينها بشكل صحيح
عن طريق الـ Constraints والقيود التي تم وضعها على الـ Database وعن طريق التحقق من البيانات والعمليات قبل تنفيذها
مثال على عدم التناسق
المبدأ شامل أي شيء قد يؤدي إلى تعارض البيانات أو تخزينها بشكل خاطئ
أذكر مثال أنني كنت أحدث صورتي الشخصية في أحد المواقع
وبعد تحديث الصورة قامت الصفحة بعرض الصورة الجديدة
لكن الغريب أن تطبيق الهاتف الخاص بالموقع ظل يعرض الصورة القديمة لعدة أيام
وصورتي القديمة كانت عند بعض الأشخاص والصورة الجديدة تظهر عند البعض الآخر
وهكذا ... هذا أيضًا يدخل ضمن مبدأ الـ Consistency
وفي هذه الحالة يوجد عدم تناسق بين بيانات الشخص عبر المنصات المختلفة والأجهزة المختلفة
لعل السبب قد يكون Caching أو CDN أو أن بياناتي تحدثت في Database في أماكن ومناطق مختلفة ولم تتم مزامنتها بشكل صحيح
أو تأخرت عملية التحديث في بعض الأماكن ولم تتم بشكل سريع وهكذا
لكن هذا مبدأ الـ Consistency بشكل عام، نحن هنا نتكلم عن الـ Consistency في الـ Transaction الواحدة
وهو أن الـ Transaction يجب أن تحترم القيود والقواعد التي تم وضعها على الـ Database ولا تخالفها
وأن تحدث البيانات بشكل صحيح ومتناسق ولا توجد بها أي تعارضات أو تناقضات
تطبيق بسيط لفائدة الـ Consistency
لنتخيل أن لدينا جدول للـ Products وجدول آخر للـ Categories وجدول آخر للـ ProductCategories
بحيث أن هناك أكثر من Product لديه أو ينتمي إلى أكثر من Category وهذا العلاقة تسمى Many to Many لذا سيتم تخزينها في جدول الـ ProductCategories
ونتخيل أن الـ Database تحتوي على البيانات التالية
Products Table
+----+--------+
| id | name |
+----+--------+
| 10 | Laptop |
| 20 | Mouse |
| 30 | Chair |
+----+--------+
Categories Table
+-----+--------+
| id | name |
+-----+--------+
| 100 | Tech |
| 200 | Home |
+-----+--------+
ProductCategories Table
+----+------------+-------------+
| id | product_id | category_id |
+----+------------+-------------+
| 1 | 10 | 100 |
| 3 | 20 | 100 |
| 2 | 30 | 100 |
| 4 | 30 | 200 |
+----+------------+-------------+
الآن لنفترض أننا نريد إضافة منتج جديد ونريد أن ينتمي إلى الفئة Tech
ونريد أن نتأكد من أن الـ Product سيتم تخزينه بشكل صحيح وأنه سينتمي إلى الفئة Tech
وأيضا سيتم إضافتهما في جدول الـ ProductCategories
public function addProduct(Request $request)
{
$request->validate([
'name' => 'required|string',
'category_id' => 'required|integer|exists:categories,id',
]);
Product::create([
'name' => $request->name,
]);
return response()->json([
'message' => 'The product has been added successfully',
], 201);
}
حسنًا هذه الدالة تقوم بإضافة منتج جديد وتقوم بتخزينه في جدول الـ Products
أين المشكلة هنا ؟ .. هل الدالة تنفذ المطلوب ؟
الإجابة هي لا
لأن الدالة لا تقوم بتخزين الـ Product في جدول الـ ProductCategories
بالتالي لن يتم تخزين العلاقة بين الـ Product والـ Category وهذا لا يعد Consistency
انتظر هذا خطأ بشري ؟
حسنًا ومن قال أن الـ Consistency سيحميك من الأخطاء البشرية ؟
الـ Consistency مبدأ يهتم بالبيانات والعمليات التي تخزن في الـ Database
لكن هناك أمور لن يستطيع مبدأ الـ Consistency أو حتى الـ ACID حمايتك منها
وهي هل أنت كتبت الدالة بشكل صحيح من الأساس ؟ الـ Consistency لن يقول لك لقد نسيت كتابة الجزء الخاص بالـ ProductCategories
مبدأ الـ Consistency ينظر إلى تطبيقك بشكل عام ويقول لك هل البيانات التي تم تخزينها في الـ Database متناسقة وصحيحة أم لا
ففي بعض الحالات يكون الـ Consistency مجرد كلام نظري وليس عملي مثل الحالة السابقة يجب على الدالة أن تنفذ المطلوب بشكل صحيح
لكن ماذا لو نسيت شيء هل سيحميك الـ Consistency من هذا الخطأ ؟ بالطبع لا فهو لن يكتب الدالة نيابة عنك
هناك حدود لكل شيء والـ Consistency لن يحميك من الأخطاء البشرية
الـ Consistency قد يحميك وينبهك من الأخطاء التي قد تحدث بسبب الـ Database أو الـ Transaction ولكن ليس من الأخطاء البشرية
الآن لنقم بتحسين الدالة السابقة ونضع الجزء الخاص بالـ ProductCategories
public function addProduct(Request $request)
{
$request->validate([
'name' => 'required|string',
'category_id' => 'required|integer|exists:categories,id',
]);
$product = Product::create([
'name' => $request->name,
]);
ProductCategory::create([
'product_id' => $product->id,
'category_id' => $request->category_id,
]);
return response()->json([
'message' => 'The product has been added successfully',
], 201);
}
حسنًا الآن الدالة تقوم بإضافة المنتج وتقوم بإضافته إلى الفئة المحددة وتخزينه في جدول الـ ProductCategories
هل قد يحدث خطأ هنا ؟
الإجابة هي نعم لكن أين وكيف ؟
ماذا لو عندما حاولنا تخزين الـ Product في الـ ProductCategories حدث خطأ ما ؟ حصل Database Exception أو Server Error أو أي شيء آخر
في هذه الحالة الـ Product قد تم تخزينه في الـ Products ولكن لم يتم تخزينه في الـ ProductCategories
هنا أيضًا الـ Database لن تكون متناسقة أو تتبع مبدأ الـ Consistency لأنها بها خلل بحيث الـ Product لديه Category ولكن لم يتم تخزينه في الـProductCategories
الحل باستخدام Transaction
ماذا نفعل الآن ؟ كيف نتجنب هذا الخطأ ؟
نحتاج شيء يضمن لنا أنه إذا حدث خطأ في أي جزء من الـ Transaction فسيتم التراجع عن كل شيء تم تنفيذه ولن يتم تطبيق أي شيء على الـ Database
هل يذكرك هذا بشيء ؟
يذكرنا بالطبع بمبدأ الـ Atomicity والذي تحدثنا عنه في المقالة السابقة مبدأ الـ Atomicity
لذا سنقوم بوضع كل شيء داخل Transaction هكذا إذا حدث أي خطأ في أي جزء من أجزاء الـ Transaction
فسيتم التراجع عن كل شيء ولن يتم تطبيق أي شيء على الـ Database
public function addProduct(Request $request)
{
$request->validate([
'name' => 'required|string',
'category_id' => 'required|integer|exists:categories,id',
]);
DB::transaction(function () use ($request) {
$product = Product::create([
'name' => $request->name,
]);
ProductCategory::create([
'product_id' => $product->id,
'category_id' => $request->category_id,
]);
});
return response()->json([
'message' => 'The product has been added successfully',
], 201);
}
الآن الدالة تقوم بإضافة المنتج وتقوم بإضافته إلى الفئة المحددة وتخزينه في جدول الـ ProductCategories
الدالة من الناحية العملية تبدو جيدة وتقوم بكل ما نريد
وأيضًا لاحظ أننا عندما وضعنا الدالة داخل Transaction هكذا سيقوم مبدأ الـ Consistency بجزءه العملي وهو ضمان أن البيانات تتبع الـ Constraints والقيود
الموجودة على الـ Database
وأيضًا ضمننا معنا مبدأ الـ Atomicity وهو ساعدنا في حال حدوث Exception ونحتاج للتراجع عن كل شيء تم تنفيذه
بالتالي مبدأ الـ Atomicity ساعدنا في تحقيق مبدأ الـ Consistency
ملخص
مبدأ الـ Consistency مبدأ عام وأحيانًا قد يكون مجرد كلام نظري وليس عملي كثيرًا
لكن ما يهمنا أن الـ Transaction تم بناءها على بعض المبادئ ومن ضمنها مبدأ الـ Consistency ليضمن عدم تلف البيانات أو تخزينها بشكل خاطئ
عن طريق احترام الـ Constraints والقيود الموجودة على الـ Database والتحقق من البيانات قبل تنفيذها
مثل التحقق من الـ Foreign Key والـ Unique والـ Primary Key وغيرها
لكن يوجد حدود عملية خارجة عن نطاق الـ Consistency وهي الأخطاء البشرية والتي لا يمكن للـ Consistency حمايتك منها
لكنها تخالف مبدأ الـ Consistency لأنك كمبرمج نفذت الدالة بشكل خاطئ من الأساس وليس بسبب الـ Database