معالجة المعاملات

معالجة المعاملات

🌍 تشبيه من الحياة الواقعية

تخيّل تحويل بنكي — تحول 1000 من الحساب A إلى الحساب B:

  1. خصم 1000 من الحساب A
  2. إضافة 1000 إلى الحساب B

إذا نجحت الخطوة 1 لكن الخطوة 2 فشلت (مثل: انهيار النظام)، فإن A فقد أموالاً لكن B لم يستلمها — هذه مشكلة كبيرة.

المعاملة تربط هاتين الخطوتين في "عملية ذرية": إما أن تنجح الخطوتان معاً (COMMIT) أو يتم التراجع عنهما معاً (ROLLBACK). لن يكون هناك حالة "مكتملة نصفياً".


🎯 المفاهيم الأساسية

ما هي المعاملة

المعاملة هي سلسلة غير قابلة للتقسيم من عمليات SQL التي إما أن تُنفَّذ بنجاح جميعها أو يتم التراجع عنها جميعها. إنها الآلية الأساسية لضمان اتساق البيانات في قواعد البيانات.

خصائص ACID

الخاصية بالإنجليزية المعنى
الذرية Atomicity جميع العمليات في المعاملة إما أن تنجح أو يتم التراجع عنها
الاتساق Consistency قاعدة البيانات تنتقل من حالة متسقة إلى أخرى
العزل Isolation المعاملات المتزامنة لا تتداخل مع بعضها البعض، كما لو أنها تُنفَّذ تسلسلياً
الدوام Durability بمجرد الالتزام، يتم حفظ البيانات بشكل دائم، حتى لو انهار النظام
💡 نصيحة للحفظ: A-C-I-D — الذرية أولاً، الدوام أخيراً، مثل سلسلة حماية متكاملة.

BEGIN / COMMIT / ROLLBACK

SQL
-- بدء معاملة
BEGIN;  -- أو START TRANSACTION

-- تنفيذ سلسلة من العمليات
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;

-- كل شيء نجح، التزام
COMMIT;

-- حدث خطأ، تراجع
ROLLBACK;

SAVEPOINT — نقاط الحفظ

تعيين "نقطة تحقق" داخل معاملة. يمكنك التراجع إلى نقطة حفظ محددة دون التأثير على العمليات السابقة لها.

SQL
BEGIN;

INSERT INTO orders VALUES (1020, 101, 1, '2026-06-28', 500.00, 'pending');
SAVEPOINT sp1;

INSERT INTO order_items VALUES (1020, 1, 2, 100.00);
SAVEPOINT sp2;

-- إذا كانت الخطوة الثانية بها خطأ، تراجع فقط إلى sp1
ROLLBACK TO sp1;

-- الاحتفاظ بعمليات الخطوة الأولى
COMMIT;
الأمر الغرض
SAVEPOINT name تعيين نقطة حفظ
ROLLBACK TO name التراجع إلى نقطة الحفظ المحددة (يحتفظ بالعمليات قبل نقطة الحفظ)
RELEASE SAVEPOINT name حذف نقطة الحفظ

مستويات عزل المعاملات

عندما تعمل عدة معاملات على نفس البيانات في نفس الوقت، قد تحدث المشاكل التالية:

المشكلة الوصف مثال
قراءة غير نظيفة قراءة بيانات لم يُلتزم بها بعد من معاملة أخرى المعاملة A تعدّل بيانات لكنها لم تلتزم؛ المعاملة B تقرأ القيمة المعدّلة
قراءة غير قابلة للتكرار قراءة نفس الصف مرتين في نفس المعاملة تعطي نتائج مختلفة المعاملة A تقرأ نفس الصف مرتين؛ بينهما، المعاملة B تعدّل ذلك الصف وتلتزم به
قراءة شبحية تنفيذ نفس الاستعلام مرتين في نفس المعاملة يعطي عدد صفوف مختلف المعاملة A تستعلم مرتين؛ بينهما، المعاملة B تُدرج صفوفاً جديدة

يُعرّف SQL أربعة مستويات عزل:

مستوى العزل قراءة غير نظيفة قراءة غير قابلة للتكرار قراءة شبحية الوصف
READ UNCOMMITTED ✅ ممكن ✅ ممكن ✅ ممكن المستوى الأقل، نادراً ما يُستخدم
READ COMMITTED ❌ لا ✅ ممكن ✅ ممكن الافتراضي في Oracle/PostgreSQL
REPEATABLE READ ❌ لا ❌ لا ✅ ممكن الافتراضي في MySQL
SERIALIZABLE ❌ لا ❌ لا ❌ لا المستوى الأعلى، أسوأ أداء
SQL
-- عرض مستوى العزل الحالي
SELECT @@transaction_isolation;

-- تعيين مستوى العزل
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

الجمود (Deadlocks)

يحدث الجمود عندما تكون معاملتان تنتظران بعضهما البعض لإطلاق الموارد:

TEXT
المعاملة A: تُقفل الجدول 1 → تنتظر الجدول 2
المعاملة B: تُقفل الجدول 2 → تنتظر الجدول 1
→ انتظار إلى الأبد، لا يمكن إكمال أبداً

كيف تتعامل قاعدة البيانات معه: تكتشف الجمود تلقائياً، تختار معاملة واحدة كـ "ضحية" وتُرجعها، مما يسمح للأخرى بالاستمرار.

استراتيجيات تجنب الجمود:

أفضل الممارسات

المبدأ الوصف
حافظ على المعاملات قصيرة تقليل وقت الاحتفاظ بالأقفال، تحسين التزامن
لا تنتظر مدخلات المستخدم في معاملة يجب أن تكتمل المعاملات بسرعة
استخدم مستويات عزل مناسبة لا تستخدم المستوى الأعلى كافتراضي
استخدم ترتيب وصول ثابت تقليل احتمالية الجمود
أضف معالجة الأخطاء تراجع فوراً عند حدوث أخطاء

📝 الأساسيات

SQL
-- بدء معاملة
BEGIN;  -- MySQL, PostgreSQL
START TRANSACTION;  -- مدعوم أيضاً في MySQL

-- الالتزام بالمعاملة (جميع العمليات تأخذ تأثيراً دائماً)
COMMIT;

-- التراجع عن المعاملة (التراجع عن جميع العمليات)
ROLLBACK;

-- نقاط الحفظ
SAVEPOINT savepoint_name;
ROLLBACK TO savepoint_name;
RELEASE SAVEPOINT savepoint_name;

-- تعيين مستوى العزل
SET TRANSACTION ISOLATION LEVEL isolation_level;
-- مستويات العزل: READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

-- تعيين مستوى العزل العام (يؤثر على جميع الاتصالات الجديدة)
SET GLOBAL TRANSACTION ISOLATION LEVEL isolation_level;

-- مفتاح الالتزام التلقائي (MySQL الافتراضي هو ON)
SET autocommit = 0;  -- تعطيل الالتزام التلقائي، يتطلب COMMIT يدوي
SET autocommit = 1;  -- تفعيل الالتزام التلقائي (الافتراضي)
💡 نصيحة:

  • MySQL الافتراضي هو autocommit = 1، حيث يتم الالتزام التلقائي لكل جملة SQL. قبل استخدام المعاملات، نفّذ BEGIN أو SET autocommit = 0
  • جمل DDL (CREATE، ALTER، DROP) تلتزم ضمنياً بالمعاملة الحالية
  • عند قطع الاتصال، يتم التراجع تلقائياً عن المعاملات غير الملزمة

📌 أمثلة

مثال: معاملة إنشاء طلب (طلب + خصم المخزون) (الصعوبة ⭐⭐)

SQL
-- السيناريو: عميل يضع طلب منتج؛ يجب إنشاء الطلب وخصم المخزون في نفس الوقت
BEGIN;

-- الخطوة 1: إنشاء الطلب
INSERT INTO orders (order_id, customer_id, employee_id, order_date, total_amount, status)
VALUES (1020, 101, 1, '2026-06-28', 6999.00, 'pending');

-- الخطوة 2: خصم المخزون
UPDATE products SET stock = stock - 1 WHERE product_id = 1;

-- الخطوة 3: التحقق من كفاية المخزون (تراجع إذا كان المخزون < 0)
-- عملياً، يتم التعامل مع هذا عادةً بواسطة منطق التطبيق أو المُحفِّزات

-- كل شيء نجح، التزام
COMMIT;
▶ جرّب الكود

إذا حدث خطأ في منتصف الطريق:

SQL
BEGIN;

INSERT INTO orders (order_id, customer_id, employee_id, order_date, total_amount, status)
VALUES (1021, 102, 3, '2026-06-28', 129.00, 'pending');

UPDATE products SET stock = stock - 1 WHERE product_id = 2;

-- افترض أننا اكتشفنا عدم كفاية المخزون، تراجع عن المعاملة بالكامل
ROLLBACK;
-- كل من الطلب والمخزون يعودان إلى حالتهما قبل المعاملة

مثال: استخدام SAVEPOINT للتراجع الجزئي (الصعوبة ⭐⭐⭐)

SQL
BEGIN;

-- الطلب الأول: ناجح
INSERT INTO orders VALUES (1022, 103, 4, '2026-06-28', 3500.00, 'pending');
UPDATE products SET stock = stock - 1 WHERE product_id = 4;
SAVEPOINT after_first_order;

-- الطلب الثاني: خطأ
INSERT INTO orders VALUES (1023, 104, 4, '2026-06-28', 2200.00, 'pending');
UPDATE products SET stock = stock - 1 WHERE product_id = 5;
SAVEPOINT after_second_order;

-- اكتشفنا مشكلة في الطلب الثاني، تراجع إلى ما بعد الأول
ROLLBACK TO after_first_order;

-- الطلب الأول لا يزال صالحاً، التزام
COMMIT;
-- النتيجة: الطلب 1022 محفوظ، الطلب 1023 تم التراجع عنه
▶ جرّب الكود

التحقق:

SQL
SELECT order_id, total_amount, status FROM orders WHERE order_id >= 1022;
TEXT
order_id | total_amount | status
---------+-------------+--------
    1022 |     3500.00 | pending

الشرح: ROLLBACK TO after_first_order يلغي فقط العمليات بعد نقطة الحفظ. الطلب الأول وخصم المخزون محفوظان.


🎬 تدريب على السيناريوهات

السيناريو 1: تعديل رواتب الموظفين دفعة واحدة (مع معالجة الأخطاء)

SQL
BEGIN;

-- رفع راتب قسم المبيعات بنسبة 10%
UPDATE employees 
SET salary = salary * 1.10 
WHERE department_id = (SELECT department_id FROM departments WHERE department_name = 'Sales');

SAVEPOINT after_sales_raise;

-- رفع راتب قسم التكنولوجيا بنسبة 8%
UPDATE employees 
SET salary = salary * 1.08 
WHERE department_id = (SELECT department_id FROM departments WHERE department_name = 'Tech');

SAVEPOINT after_tech_raise;

-- افترض أن موافقة الميزانية لم تمر، فقط التراجع عن رفع راتب التكنولوجيا
ROLLBACK TO after_sales_raise;

-- رفع راتب المبيعات محفوظ، التزام
COMMIT;

النقطة الأساسية: SAVEPOINT يُمكّن "التراجع الجزئي"، مناسب للعمليات الدفعية التي تتطلب تحكماً مرناً.

السيناريو 2: محاكاة تحويل والتعامل مع الجمود

SQL
-- الجلسة A: تحويل ميزانية من القسم 1 إلى القسم 2
BEGIN;
UPDATE departments SET budget = budget - 50000 WHERE department_id = 1;
-- انتظر لحظة...
UPDATE departments SET budget = budget + 50000 WHERE department_id = 2;
COMMIT;

-- الجلسة B: في نفس الوقت تحويل ميزانية من القسم 2 إلى القسم 1 (اتصال آخر)
BEGIN;
UPDATE departments SET budget = budget - 30000 WHERE department_id = 2;
UPDATE departments SET budget = budget + 30000 WHERE department_id = 1;
COMMIT;

منع الجمود:

-- كلا الجلستين تصلان إلى الأقسام بترتيب تصاعدي حسب department_id
-- الجلسة A:
BEGIN;
UPDATE departments SET budget = budget - 50000 WHERE department_id = 1;  -- قفل 1 أولاً
UPDATE departments SET budget = budget + 50000 WHERE department_id = 2;  -- ثم قفل 2
COMMIT;

-- الجلسة B:
BEGIN;
UPDATE departments SET budget = budget + 30000 WHERE department_id = 1;  -- أيضاً قفل 1 أولاً
UPDATE departments SET budget = budget - 30000 WHERE department_id = 2;  -- ثم قفل 2
COMMIT;

النقطة الأساسية: استخدام ترتيب وصول ثابت هو أبسط وأكثر طريقة فعالية لتجنب الجمود.


❓ أسئلة شائعة

س: MySQL افتراضياً يلتزم تلقائياً — كيف أستخدم المعاملات؟ ج: MySQL الافتراضي هو autocommit = 1، حيث يتم الالتزام التلقائي لكل جملة SQL. لاستخدام المعاملات، نفّذ BEGIN (أو START TRANSACTION) أولاً؛ الجمل SQL اللاحقة لن يتم الالتزام بها تلقائياً حتى تنفّذ COMMIT أو ROLLBACK.

س: هل يمكنني التراجع بعد الالتزام؟ ج: لا. COMMIT هو نهاية المعاملة؛ بمجرد الالتزام، يتم حفظ البيانات بشكل دائم ولا يمكن التراجع عنها. "للتراجع" عن بيانات ملزمة، يجب تنفيذ عملية عكسية في معاملة جديدة (مثل: UPDATE للقيمة الأصلية).

س: أي مستوى عزل يجب أن أختار؟ ج: لمعظم السيناريوهات، استخدم الافتراضي في قاعدة البيانات (MySQL الافتراضي REPEATABLE READ، Oracle/PostgreSQL الافتراضي READ COMMITTED). استخدم SERIALIZABLE فقط عندما تحتاج صراحةً إلى منع القراءات الشبحية وتقبل تكلفة الأداء.

س: هل جمل DDL (CREATE TABLE، ALTER TABLE) تتحكم بها المعاملات؟ ج: لا. جمل DDL تلتزم ضمنياً بالمعاملة الحالية. بعد تنفيذ DDL في معاملة، لا يمكن التراجع عن جمل SQL السابقة. هذا سلوك MySQL؛ في PostgreSQL، يمكن التراجع عن DDL.


📖 ملخص

المفهوم الوصف
المعاملة مجموعة من عمليات قاعدة البيانات غير القابلة للتقسيم
ACID الذرية، الاتساق، العزل، الدوام
BEGIN بدء معاملة
COMMIT الالتزام بالمعاملة، جعلها دائمة
ROLLBACK التراجع عن المعاملة، التراجع عن كل شيء
SAVEPOINT نقطة تحقق داخل معاملة، تدعم التراجع الجزئي
مستوى العزل يتحكم في الرؤية بين المعاملات المتزامنة
الجمود معاملتان تنتظران بعضهما البعض؛ قاعدة البيانات تكتشف تلقائياً وتُرجع إحداهما

📝 تمارين

  1. اكتب معاملة تُدرج طلباً جديداً في جدول orders مع خصم المخزون المقابل من جدول products. إذا كان المخزون غير كافٍ، تراجع عن المعاملة بالكامل.
  2. استخدم SAVEPOINT لتنفيذ معاملة تُدرج 3 سجلات طلبات، ثم تراجع عن الثالث مع الاحتفاظ بالأولين.
  3. تحقق من مستوى العزل الافتراضي في قاعدة البيانات الخاصة بك وجرّب تعيينه إلى READ COMMITTED لملاحظة التأثير على القراءات والكتابات المتزامنة.
  4. سؤال تفكير: إذا استغرقت معاملة وقتاً طويلاً للتنفيذ، ما تأثيرها على المعاملات الأخرى؟ كيف يمكن تحسين ذلك?

الدرس التالي

👉 22-stored-procedures - الإجراءات المخزنة: تعلّم إنشاء واستدعاء الإجراءات المخزنة، المُعامِلات المدخلة/المخرَجة، جمل التحكم في التدفق، والتطبيقات العملية للإجراءات المخزنة.

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%