Database Transactions في Laravel الدليل الكامل لحماية البيانات من الفساد
لماذا سلامة البيانات (Data Integrity) مسألة مصيرية؟
في تطبيقات Laravel الواقعية، أخطر المشاكل اللي ممكن تواجهك مش الأخطاء الظاهرة أو الـ Bugs اللي بتطلعلك في الـ Logs، لكن المشاكل اللي بتحصل بهدوء… من غير ما تحس.
ممكن تطبيقك يفضل شغال، المستخدمين مبسوطين، والدنيا تمام، لكن الداتابيز من جوه تكون دخلت في حالة غير متناسقة، وده مع الوقت بيؤدي لخسائر حقيقية.
سلامة البيانات معناها إن حالة النظام دايمًا منطقية ومتوافقة مع الواقع. أي كسر للمبدأ ده هو قنبلة موقوتة.
المشكلة الشائعة في تطبيقات Laravel
كتير من المطورين بيكتبوا كود شكله بسيط وسليم، وغالبًا بيعدي من غير مشاكل في الاختبارات، لكنه بيكون خطر جدًا في بيئة الإنتاج.
public function subscribe(User $user)
{
// إنشاء الاشتراك
$user->subscriptions()->create([
'plan' => 'premium',
'status' => 'active',
]);
// تحصيل المبلغ (API خارجي)
Stripe::charge($user->id, 100);
}
الكود ده منطقي ظاهريًا: بننشئ اشتراك، وبعدها نحصّل الفلوس. المشكلة إننا بنتعامل هنا مع مصدرين مختلفين تمامًا.
الداتابيز تحت سيطرتك الكاملة، لكن الـ API الخارجي زي Stripe مش مضمون في أي لحظة.
سيناريو الفشل: الكارثة الصامتة
خلّينا نمشي بالسيناريو الواقعي:
المستخدم ضغط على زر الاشتراك، Laravel نفّذ إنشاء الاشتراك بنجاح، وبعدها مباشرة حصل خطأ في الاتصال بـ Stripe.
النتيجة؟ الاشتراك اتسجل في الداتابيز، حالته نشطة، لكن ولا جنيه اتدفع.
مفيش Error واضح، ومفيش Crash، لكن السيستم دخل في حالة غير منطقية.
النوع ده من الأخطاء هو الأخطر، لأنه بيكمل معاك شهور قبل ما تكتشفه.
ليه الكود ده خطر رغم إنه شغال؟
الغلطة مش في PHP ولا في Laravel، الغلطة في التفكير.
العمليات دي المفروض تتعامل كعملية واحدة، مش خطوات منفصلة.
لما تسيب كل خطوة تنفذ لوحدها، إنت فعليًا بتكسر مبدأ أساسي في تصميم الأنظمة: إما كل حاجة تتم، أو ولا حاجة تتم.
ما هي Database Transactions؟
Database Transaction هي آلية بتخلي مجموعة أوامر تتنفذ كوحدة واحدة.
لو أي خطوة فشلت، الداتابيز بترجع لكل حالتها قبل بداية العملية، كأن ولا حاجة حصلت.
ده بيضمن إن الداتابيز دايمًا في حالة متناسقة، مهما حصل فشل في النص.
الحل الصحيح باستخدام Transactions في Laravel
Laravel موفّر لك الحل ده بشكل بسيط جدًا:
DB::transaction(function () use ($user) {
$user->subscriptions()->create([
'plan' => 'premium',
'status' => 'active',
]);
Stripe::charge($user->id, 100);
});
دلوقتي السيناريو اختلف تمامًا.
لو Stripe فشل، Laravel هيعمل Rollback تلقائي، والاشتراك هيتشال من الداتابيز، وكأن العملية ما بدأتش.
كيف Laravel يتعامل مع Rollback تلقائيًا؟
أي Exception بتحصل جوه الـ transaction بتخلي Laravel يرجّع كل التغييرات اللي حصلت.
إنت مش محتاج تكتب كود إضافي، ولا تمسك Errors بإيدك.
ده بيخلي الكود أنضف، وأسهل في الصيانة، وأكثر أمانًا.
متى يجب استخدام Database Transactions؟
استخدمها في أي عملية فيها: دفع، اشتراكات، خصم رصيد، إنشاء أكثر من سجل مترابط، أو أي منطق تجاري حساس.
لو العملية ممكن تسبب خسارة فلوس أو بيانات، يبقى لازم Transaction.
أخطاء شائعة عند استخدام Transactions
من الأخطاء المنتشرة إنك تستخدم Transaction مع عمليات طويلة جدًا، أو تحط جواها Logic مش متعلق بالداتابيز.
حاول تخليها قصيرة، ومركزة، ومخصصة فقط للأجزاء الحرجة.
الخلاصة
Database Transactions مش Feature اختيارية، دي أساس لأي تطبيق Laravel محترم.
الكود اللي “شغال” مش دايمًا كود آمن، وأي تجاهل لسلامة البيانات ثمنه بيتدفع متأخر… وغالي.
استخدم Transactions، واحمي تطبيقك من أخطاء مش هتعرف بوجودها غير بعد فوات الأوان.