بنناجح
المرحلة 1: الأساس · الدرس 1 من 3 · 20 دقيقة

يعني إيه Transaction؟

أي عملية حقيقية في الأبلكيشن عبارة عن كذا تعديل في الداتابيز لازم يحصلوا مع بعض أو ميحصلش ولا واحد. الدرس ده بيعرّف الترانزاكشن، ويوريك هي بتبدأ وتخلص إزاي، والحالات اللي بتمر بيها، والفرق الكبير بين PostgreSQL و MySQL لما Error يطلع في النص.

في الدرس ده هتتعلم
  • تعرّف الـ Transaction وتعرف إمتى لازم تستخدمها
  • تستخدم BEGIN و COMMIT و ROLLBACK وتفهم الـ Autocommit
  • تعرف حالات الترانزاكشن من أول ما تبدأ لحد ما تخلص
  • تفهم بيحصل إيه لما Error يطلع في النص في PostgreSQL وفي MySQL

1. المشكلة

عميل اشترى من المتجر. العملية دي في الداتابيز عبارة عن 4 حاجات:

checkout.sql
INSERT INTO orders (id, user_id, total) VALUES (501, 7, 1200);
INSERT INTO order_items (order_id, product_id, qty) VALUES (501, 33, 1);
UPDATE products SET stock = stock - 1 WHERE id = 33;
UPDATE wallets  SET balance = balance - 1200 WHERE user_id = 7;

لو السيرفر وقع بعد الجملة التالتة: الأوردر اتعمل، والمخزون نقص، والفلوس ماتخصمتش. ولو الجملة الرابعة فشلت لأن الرصيد مش كفاية: الأوردر موجود والمخزون نقص على الفاضي. وحتى من غير ما حاجة تقع، لو حد قرا الداتا بين الجملة الأولى والرابعة، هيشوف أوردر “مدفوع” والفلوس لسه في المحفظة.

المطلوب إن الأربع جمل دول يبقوا عملية واحدة من وجهة نظر أي حد: يا حصلوا كلهم، يا ولا واحد فيهم حصل.

2. التعريف

checkout.sql
BEGIN;                                   -- أو START TRANSACTION
INSERT INTO orders (id, user_id, total) VALUES (501, 7, 1200);
INSERT INTO order_items (order_id, product_id, qty) VALUES (501, 33, 1);
UPDATE products SET stock = stock - 1 WHERE id = 33;
UPDATE wallets  SET balance = balance - 1200 WHERE user_id = 7;
COMMIT;                                  -- كله اتثبت مرة واحدة
-- أو ROLLBACK;                          -- كله اتلغى

القاعدة البسيطة: أي تعديلين لازم يحصلوا مع بعض، حطهم في ترانزاكشن واحدة. ولو جملة واحدة بس، الداتابيز بتعملها ترانزاكشن لوحدها أصلاً (وهو ده الـ Autocommit).

الترانزاكشن بتخلّي كذا تعديل يبانوا للعالم كأنهم تعديل واحد: يا كله يا مفيش.

3. الـ Autocommit

يعني لو بعت الأربع جمل اللي فوق من غير BEGIN، دول 4 ترانزاكشنز منفصلين، وكل واحدة بتتثبت لوحدها. وده أشهر سبب للداتا اللي “نص متسجلة” في الأبلكيشنز.

MySQL PostgreSQL
الافتراضي autocommit = 1 كل جملة ترانزاكشن لوحدها
تبدأ ترانزاكشن START TRANSACTION أو BEGIN BEGIN أو START TRANSACTION
تقفل الـ Autocommit للـ Session SET autocommit = 0 (أي جملة بعدها بتفتح ترانزاكشن لحد ما تعمل COMMIT) مفيش إعداد على السيرفر، بيتعمل في الـ Client (زي \set AUTOCOMMIT off في psql)

4. حالات الترانزاكشن

الحالة معناها
Active شغالة: بتقرا وبتكتب
Partially Committed آخر جملة خلصت، وطلبت COMMIT، والداتابيز بتكتب الـ Log على الديسك
Committed الـ Log اتكتب على الديسك، والتعديلات مضمونة ومحدش يقدر يلغيها
Failed حصل Error، ومينفعش تكمّل
Aborted اتعملها ROLLBACK، وكل أثرها اتشال

اللحظة الفاصلة هي الانتقال من Partially Committed لـ Committed: بيحصل لما سجل الـ COMMIT يتكتب في الـ Log على الديسك (ده درس الـ Durability). قبلها، لو الكهربا قطعت، الترانزاكشن كأنها ماحصلتش. بعدها، حتى لو الكهربا قطعت، التعديلات موجودة.

5. لما Error يطلع في النص

هنا فيه فرق كبير جداً بين الداتابيزين، وبيعمل Bugs حقيقية لو مش واخد بالك منه:

جملة فشلت في نص الترانزاكشنجرّب بنفسك
في الداتابيزorders0stock(33)5
الترانزاكشن⏱بعد كده
  1. BEGIN; INSERT INTO orders (id, user_id) VALUES (501, 7);INSERT 0 11
  2. INSERT INTO orders (id, user_id) VALUES (501, 8);ERROR: duplicate key2
  3. UPDATE products SET stock = stock - 1 WHERE id = 33;ERROR: current transaction is aborted3
  4. COMMIT;ROLLBACK4
  5. 5SELECT count(*) FROM orders;0
▶

دوس ▶ شغّل، أو امشي خطوة خطوة بالأسهم.

استثناءات مهمة في MySQL: الـ Deadlock بيلغي الترانزاكشن كلها (مش الجملة بس). أما الـ Lock wait timeout فبيلغي الجملة بس (إلا لو innodb_rollback_on_timeout = ON).

الخلاصة العملية: الكود لازم يتعامل مع أي Error جوه ترانزاكشن على إنه “الغي كل حاجة”. ده بالظبط اللي DB::transaction في Laravel بيعمله: أي Exception يطلع بيعمل ROLLBACK للترانزاكشن كلها، في الداتابيزين.

في PostgreSQL أي Error بيقفل الترانزاكشن لحد الـ ROLLBACK. في MySQL الجملة بس اللي بتتلغى والباقي ممكن يتثبت. اكتب كودك على إن أي Error = ROLLBACK كامل.

6. أسئلة الإنترفيو

فكّر في إجابتك الأول، وبعدين افتح السؤال.

01يعني إيه Transaction؟ وإمتى تستخدمها؟

مجموعة عمليات بتتعامل كوحدة واحدة: يا كلها تتثبت بـ COMMIT، يا كلها تتلغى بـ ROLLBACK، ومحدش يشوف نتايجها قبل الـ COMMIT. بتستخدمها لما كذا تعديل لازم يحصلوا مع بعض، زي أوردر وخصم مخزون وخصم رصيد.

02يعني إيه Autocommit؟ وإيه خطره؟

الوضع الافتراضي: كل جملة من غير BEGIN بتبقى ترانزاكشن لوحدها وبتتثبت أوتوماتيك. خطره إنك تبعت كذا جملة مرتبطة من غير BEGIN فيبقوا ترانزاكشنز منفصلين، ولو حاجة وقعت في النص الداتا تبقى نصها متسجل.

03إيه اللي بيحصل في PostgreSQL لو جملة فشلت جوه ترانزاكشن؟ وفي MySQL؟

PostgreSQL: الترانزاكشن كلها بتدخل حالة aborted، وأي جملة بعدها ترفض، والـ COMMIT بيتحول لـ ROLLBACK. MySQL: الجملة اللي فشلت بس اللي بتتلغى، والترانزاكشن بتكمل، والـ COMMIT بيثبت الجمل اللي نجحت. ما عدا الـ Deadlock اللي بيلغي الترانزاكشن كلها.

04إمتى الترانزاكشن تعتبر Committed فعلاً؟

لما سجل الـ COMMIT يتكتب في الـ Log (WAL أو Redo Log) على الديسك. قبلها لو السيرفر وقع كأنها ماحصلتش، وبعدها التعديلات مضمونة حتى لو الكهربا قطعت.

علّم عليه لما تقدر تجاوب أسئلة الإنترفيو من غير ما تبص.