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

Autocommit و Savepoints و DDL

3 حاجات بتعمل مفاجآت في الشغل الحقيقي: إزاي تلغي جزء من ترانزاكشن من غير ما تلغيها كلها، والجمل اللي بتعمل COMMIT من وراك في MySQL، وليه Migration فشلت في النص بتسيب الداتابيز في PostgreSQL سليمة وفي MySQL نصها متعدّل.

في الدرس ده هتتعلم
  • تستخدم Savepoints عشان تلغي جزء من الترانزاكشن
  • تعرف الجمل اللي بتعمل Implicit Commit في MySQL
  • تفهم Transactional DDL في PostgreSQL وليه بيفرق في الـ Migrations
  • تعرف الحاجات اللي مينفعش تتعمل جوه ترانزاكشن

1. Savepoints

مثال: استيراد 1000 منتج في ترانزاكشن واحدة. لو منتج واحد فيه مشكلة، مش عايز تلغي الـ 999 التانيين:

savepoints.sql
BEGIN;
INSERT INTO products (sku, name) VALUES ('A-1', 'شاحن');

SAVEPOINT row_2;
INSERT INTO products (sku, name) VALUES ('A-1', 'سماعة');   -- ERROR: duplicate sku
ROLLBACK TO SAVEPOINT row_2;                                -- نرجع لقبل المنتج ده بس

SAVEPOINT row_3;
INSERT INTO products (sku, name) VALUES ('A-3', 'كابل');
RELEASE SAVEPOINT row_3;                                    -- خلاص مش محتاجين العلامة

COMMIT;   -- الشاحن والكابل اتثبتوا، والسماعة لأ

في PostgreSQL ده الحل الوحيد إنك تكمّل بعد Error جوه ترانزاكشن، لأن من غيره الترانزاكشن كلها بتقفل (شفناه في الدرس الأول). وفي Laravel، كل DB::transaction جوه DB::transaction تانية بيتعمل Savepoint أوتوماتيك.

بس خد بالك: الـ Savepoints مش ببلاش. في PostgreSQL كل Savepoint بيعمل Subtransaction ليها رقم، ولو الترانزاكشن فيها أكتر من 64 Subtransaction شغالين، الأداء بيقع بشكل ملحوظ على السيرفر كله (مشكلة معروفة باسم Subtransaction SLRU overflow). يعني Savepoint لكل صف في Import بمليون صف = فكرة وحشة. قسّم الشغل لـ Batches بدل كده.

الـ Savepoint بيخليك تلغي جزء من الترانزاكشن. استخدمه للأخطاء المتوقعة، مش كـ try/catch حوالين كل صف.

2. الجمل اللي بتعمل COMMIT من وراك (MySQL)

في MySQL فيه جمل لو اتنفذت جوه ترانزاكشن، بتعمل COMMIT للترانزاكشن الحالية قبلها من غير ما تقولك. ده اسمه Implicit Commit:

النوع أمثلة
DDL CREATE TABLE، ALTER TABLE، DROP TABLE، CREATE INDEX، TRUNCATE، RENAME TABLE
إدارة CREATE USER، GRANT، ANALYZE TABLE، OPTIMIZE TABLE
تحكم في الترانزاكشن START TRANSACTION / BEGIN جديد، SET autocommit = 1، LOCK TABLES
ROLLBACK مارجّعش حاجةجرّب بنفسك
في الداتابيزorders.statuspendingorders.note—
سكريبت إصلاح داتا⏱النتيجة
  1. START TRANSACTION; UPDATE orders SET status = 'cancelled' WHERE created_at < '2026-01-01';12,840 rows1
  2. ALTER TABLE orders ADD COLUMN cancel_note VARCHAR(255);OK · Implicit COMMIT2
  3. -- اكتشفنا إن الشرط غلط! ROLLBACK;OK · مفيش حاجة اترجعت3
  4. 4SELECT status FROM orders WHERE ...;cancelled
▶

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

3. الـ Migrations

ده بيفرق جداً في الـ Migrations. تخيّل Migration فيها 3 خطوات: تضيف عمود، وتنقل داتا ليه، وتمسح العمود القديم. والخطوة التانية فشلت:

PostgreSQL MySQL
الـ Migration بتتنفذ في ترانزاكشن؟ آه (Laravel بيعمل كده افتراضياً) لأ، مينفعش
لو خطوة فشلت كل الـ Migration بتتلغى، والجدول زي ما كان الخطوة الأولى اتثبتت، والجدول نصه متعدّل
تعيد تشغيلها عادي بتفشل لأن العمود موجود، ولازم تصلح بإيدك

وده سبب نصيحة مهمة لـ MySQL: Migration واحدة = تغيير واحد في الـ Schema، عشان لو فشلت يبقى سهل تعرف وقفت فين.

4. حاجات مينفعش تتعمل جوه ترانزاكشن

حتى في PostgreSQL، فيه أوامر بترفض تشتغل جوه BEGIN:

الأمر ليه
CREATE INDEX CONCURRENTLY بيحتاج يستنى ترانزاكشنز تانية تخلص على مرحلتين
VACUUM بيشتغل برة أي ترانزاكشن
CREATE DATABASE / DROP DATABASE على مستوى السيرفر
ALTER TYPE ... ADD VALUE (إصدارات قديمة) قبل PostgreSQL 12 مكانش مسموح جوه ترانزاكشن

وفي Laravel على PostgreSQL، أي Migration فيها حاجة من دول لازم تقفل الترانزاكشن بتاعتها:

database/migrations/..._add_orders_index.php
return new class extends Migration
{
    public $withinTransaction = false;   // الـ Migration دي مش هتتلف في ترانزاكشن

    public function up(): void
    {
        DB::statement('CREATE INDEX CONCURRENTLY orders_user_created ON orders (user_id, created_at)');
    }
};

في MySQL الـ DDL بيقفل الترانزاكشن، والـ Migration اللي فشلت بتسيب الجدول نصه متعدّل. في PostgreSQL الـ DDL بيتلغي مع الـ ROLLBACK، ما عدا أوامر زي CONCURRENTLY.

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

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

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

علامة جوه الترانزاكشن تقدر ترجعلها بـ ROLLBACK TO SAVEPOINT من غير ما تلغي الترانزاكشن كلها. بتستخدمه لما جزء من الشغل ممكن يفشل وعايز تكمل الباقي، وفي PostgreSQL هو الطريقة الوحيدة تكمل بعد Error جوه ترانزاكشن. وفي Laravel، الترانزاكشن جوه ترانزاكشن بتبقى Savepoint.

02يعني إيه Implicit Commit في MySQL؟

جمل زي CREATE و ALTER و DROP و TRUNCATE و LOCK TABLES و START TRANSACTION بتعمل COMMIT للترانزاكشن الحالية قبل ما تتنفذ، من غير أي تنبيه. فأي ROLLBACK بعدها مش بيرجّع اللي اتعمل قبلها.

03ليه Migration فشلت في النص أخطر في MySQL من PostgreSQL؟

PostgreSQL بيدعم Transactional DDL، فالـ Migration كلها بتتلف في ترانزاكشن، ولو فشلت كل تغييراتها بتتلغى. في MySQL كل DDL بيتثبت لوحده، فالخطوات اللي نجحت بتفضل، والجدول يفضل نصه متعدّل، وإعادة تشغيل الـ Migration بتفشل.

04ليه Savepoint لكل صف في Import كبير فكرة وحشة في PostgreSQL؟

كل Savepoint بيعمل Subtransaction، ولو الترانزاكشن فيها أكتر من 64 Subtransaction، PostgreSQL بيدخل في Subtransaction overflow والأداء بيقع على السيرفر كله. الأحسن تقسم الـ Import لـ Batches في ترانزاكشنز منفصلة.

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