ما هو الـ Transaction في قواعد البيانات؟
هذه القصاصة كانت جزءا من مقال قادم عن خصائص ACID في قواعد البيانات.
تم فصلها إلى قصاصة مستقلة لجعل المقال الأصلي أقصر، سيتم وضع رابط المقال هنا فور نشره.
الـ Transaction هو مجموعة من الـ Queries المتتالية، تُجمّع وتنفَّذ كوحدة واحدة (Logical Unit of Work).
تنفِّذ البرامج غالبا مجموعة من العمليات المرتبطة بعضها ببعض على قاعدة البيانات، فعملية تحويل مبلغ مالي من حساب لآخر في برنامج للحوالات المالية قد تجري كالآتي:
- قراءة الرصيد الموجود في الحساب الأول للتحقق من وجود رصيد كافٍ قبل التحويل منه.
- خصم مبلغ الحوالة من الحساب الأول.
- إضافة مبلغ الحوالة للحساب الثاني.
- إضافة سجل في جدول لتتبع الحوالات يُثْبِت تحويل مبلغ محدد من الحساب الأول إلى الحساب الثاني.
على مستوى قاعدة البيانات، هذه أربع عمليات مختلفة، بينما على مستوى نظام إدارة الحوالات فهي عملية واحدة (عملية تحويل).
الهدف من هذا التجميع ليس ترتيب الـ Queries فحسب، بل الـ Transaction يضمن بعض الخصائص المهمة لصحة البيانات وسلامتها، وتفصيل ذلك في بقية المقال.
ما يهمنا الآن معرفة أن الـ Transaction ينتهي بأحدى عمليتين:
COMMITROLLBACK
عملية ROLLBACK عملية تراجعٍ عن الـ Transaction، عند تنفيذ الأمر ROLLBACK يتوقف الـ Transaction ويتراجع عن جميع التغييرات التي أجراها.
من الشائع أن عملية ROLLBACK تُنفّذ عند وقوع خطأ اثناء تنفيذ الـ Transaction، لكن هذا غير دقيق، فيمكن تنفيذ عملية ROLLBACK حتى بلا خطأ.
بينما عملية COMMIT تُنهي الـ Transaction وتثبتُ التغييرات.
كيف نكتب الـ Transaction في SQL؟
المثال التالي قد يكتب هكذا في SQL:
1BEGIN;
2SELECT balance FROM accounts where id = 1;
3UPDATE accounts SET balance = balance - 100 WHERE id = 1;
4UPDATE accounts SET balance = balance + 100 WHERE id = 2;
5INSERT INTO transfer_logs (from, to, amount, sent_at) VALUES (1, 2, 100, NOW());
6COMMIT;الأمر BEGIN في المثال السابق يمثل بداية الـ Transaction، أي Query يتبعها في نفس الجلسة ينفّذ ضمن الـ Transaction، يتم انهاء الـ Transaction وتثبيت نتائج الـ Queries عند تنفيذ COMMIT.
يمكن أيضا تنفيذ ROLLBACK يدويا عند أي نقطة كما في المثال التالي:
1BEGIN;
2SELECT balance FROM accounts where id = 1;
3UPDATE accounts SET balance = balance - 100 WHERE id = 1;
4-- تذكرت أن القيمة التي يجب تحويلها هي 300 بدلا من 100
5ROLLBACK; -- تراجع عن الخطأ السابق!لاحظ في هذا المثال أنه لم يحدث خطأ أصلا على مستوى الـ Query، الـ Query سليم وتم تنفيذه بنجاح، لكن الخطأ من مدخلات كاتب الـ Query، تنفيذ ROLLBACK عند تنفيذ الـ Queries يدويا ممكن، لكن ماذا لو كنت أنفذ ذلك ضمن النظام الذي أبرمجه؟
يمكنك تنفيذ الـ queries بنفس الطريقة ضمن الكود، مثال:
1# هذا الكود مجرد مثال، سيختلف بحسب طريقة تعامل مع قاعدة البيانات من داخل الكود
2
3def transferBalance(senderAccount, receiverAccount, amount):
4 beginTransaction()
5 currentBalance = getAccountBalance(senderAccount)
6
7 if currentBalance < amount:
8 rollbackTransaction()
9 return
10
11 confirmBalanceTransfer(senderAccount, receiverAccount, amount)
12 commitTransaction()الحالة الأخيرة، هي حدوث خطأ في الـ Query كما في المثال التالي:
1BEGIN;
2SELECT balance FROM accounts where id = 1;
3UPDATE accounts SET balance = balance - 100 WHERE id = 1;
4-- باقي الـ queriesلو حصل خطأ في Query تحديث الرصيد (لو أصبح الرصيد مثلا بالسالب بينما balance معرفة كـ unsigned value)، لن يتم تنفيذ باقي الـ Queries، حيث يدخل الـ Transaction في حالة aborted ويرفض تنفيذ باقي الـ Queries، مما يجبرك على تنفيذ Rollback، غالبا ما تتم هذه العملية تلقائيا عند استخدام أي Database Client أو ORM في لغة البرمجة المستخدمة، وفي حالة عدم دعم الـ Rollback التلقائي يمكن تنفيذ الـ Rollback ضمن try... catch....
في المقال الذي سيتم نشره عن خصائص ACID في قواعد البيانات ستتضح فوائد أكبر للـ Transaction إضافة إلى الخيارات والإعدادات الممكنة وكيف تؤثر في صحة البيانات أو أداء قاعدة البيانات.