Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

SQLتنفيذ كل الأوامر أو إلغاءها كلها

  • مفهوم الـ Transaction
  • تجهيز قاعدة البيانات التي سنطبق عليها
  • طريقة وضع الكود بداخل Transaction
  • التراجع عن تنفيذ أوامر الـ Transaction

مفهوم الـ Transaction

Transaction يقصد بها مجموعة من الأوامر إما أن تتنفذ جميعها بنجاح أو لا يتم تنفيذها.

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

في حالة الشراء أونلاين قد تقع في مشاكل كارثية ما لم يتم تنفيذ جميع الخطوات بنجاح. فمثلاً في حال قمت بتحويل المال للموقع الإلكتروني و فجأةً تعطل الموقع قبل أن يسجل في قاعدة البيانات أنك قمت بشراء نسخة البرنامج و قبل أن يرسل لك كود تفعيل البرنامج الذي دفعت ثمنه فإنك ستخسر مالك.

Transaction تعني محاولة تنفيذ جميع الأوامر و في حال فشل أي أمر موضوع يجب إلغاء تنفيذ كل الأوامر التي تم تنفيذها بنجاح.

قواعد بيانات MySQL - SQL Server - Access - Oracle - SQLite جميعها تتيح لك إمكانية وضع الكود في Transaction و لكن أسلوب كتابتها تختلف قليلاً من قاعدة بيانات لأخرى.

تجهيز قاعدة البيانات التي سنطبق عليها

قم بتنفيذ الإستعلام التالي حتى تنشئ قاعدة بيانات جديدة إسمها harmash و تنشئ فيها الجداول التالية:

  • users جدول خاص لحفظ معلومات المستخدمين و قد وضعنا فيه بيانات 3 مستخدمين.
  • products جدول خاص لحفظ معلومات المنتجات و قد وضعنا فيه بيانات 5 منتجات.
  • orders جدول خاص لحفظ الطلبيات.

مثال

-- سيتم حذفها harmash في حال كان يوجد بالأساس قاعدة بيانات إسمها
DROP DATABASE IF EXISTS harmash;
-- harmash هنا قمنا بإنشاء قاعدة بيانات جديدة إسمها
CREATE DATABASE harmash;
-- harmash هنا قمنا بتحديد أن أي إستعلام جديد سيتم تنفيذه على قاعدة البيانات
USE harmash;
-- يتألف من 3 أعمدة users هنا قمنا بإنشاء جدول جديد إسمه
CREATE TABLE users (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
email VARCHAR(100)
);
-- يتألف من 3 أعمدة products هنا قمنا بإنشاء جدول جديد إسمه
CREATE TABLE products (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
available INT
);
-- يتألف من عمودين orders هنا قمنا بإنشاء جدول جديد إسمه
CREATE TABLE orders (
user_id INT,
product_id INT,
quantity INT,
sale_date DATE
);
-- أي أضفنا معلومات 3 مستخدمين ،users هنا قمنا بإضافة 3 أسطر في الجدول
INSERT INTO users VALUES (null, 'Mhamad', 'mhamad@example.com');
INSERT INTO users VALUES (null, 'Hala', 'hala@example.com');
INSERT INTO users VALUES (null, 'Sarah', 'sarah@example.com');
-- أي أضفنا معلومات 5 منتجات products هنا قمنا بإضافة 5 أسطر في الجدول
INSERT INTO products VALUES (null, 'Mouse', 86);
INSERT INTO products VALUES (null, 'Keyboard', 140);
INSERT INTO products VALUES (null, 'Printer', 54);
INSERT INTO products VALUES (null, 'Screen', 32);
INSERT INTO products VALUES (null, 'Chair', 80);
-- سيتم حذفها harmash في حال كان يوجد بالأساس قاعدة بيانات إسمها DROP DATABASE IF EXISTS harmash; -- harmash هنا قمنا بإنشاء قاعدة بيانات جديدة إسمها CREATE DATABASE harmash; -- harmash هنا قمنا بتحديد أن أي إستعلام جديد سيتم تنفيذه على قاعدة البيانات USE harmash; -- يتألف من 3 أعمدة users هنا قمنا بإنشاء جدول جديد إسمه CREATE TABLE users ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), email VARCHAR(100) ); -- يتألف من 3 أعمدة products هنا قمنا بإنشاء جدول جديد إسمه CREATE TABLE products ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200), available INT ); -- يتألف من عمودين orders هنا قمنا بإنشاء جدول جديد إسمه CREATE TABLE orders ( user_id INT, product_id INT, quantity INT, sale_date DATE ); -- أي أضفنا معلومات 3 مستخدمين ،users هنا قمنا بإضافة 3 أسطر في الجدول INSERT INTO users VALUES (null, 'Mhamad', 'mhamad@example.com'); INSERT INTO users VALUES (null, 'Hala', 'hala@example.com'); INSERT INTO users VALUES (null, 'Sarah', 'sarah@example.com'); -- أي أضفنا معلومات 5 منتجات products هنا قمنا بإضافة 5 أسطر في الجدول INSERT INTO products VALUES (null, 'Mouse', 86); INSERT INTO products VALUES (null, 'Keyboard', 140); INSERT INTO products VALUES (null, 'Printer', 54); INSERT INTO products VALUES (null, 'Screen', 32); INSERT INTO products VALUES (null, 'Chair', 80);

فيما يلي البيانات التي قمنا بإضافتها في الجدول users.

users
id username email
1 Mhamad mhamad@example.com
2 Hala mhamad@example.com
3 Sarah mhamad@example.com

فيما يلي البيانات التي قمنا بإضافتها في الجدول products.

products
id title available
1 Mouse 86
2 Keyboard 140
3 Printer 45
4 Screen 32
5 Chair 80

فيما يلي البيانات التي قمنا بإضافتها في الجدول orders.

orders
user_id product_id quantity sale_date

طريقة وضع الكود بداخل Transaction

في قواعد بيانات MySQL يجب أولاً إعلام قاعدة البيانات بأنك تريد إيقاف الحفظ التلقائي و هذه الخطوة تحتاج أن تفعلها مرة واحدة فقط و ليس عند إرسال كل إستعلام.

لإعلام قاعدة البيانات بأنك تريد إيقاف الحفظ التلقائي، يجب أن تنفذ الإستعلام التالي.

SET autocommit = OFF;
SET autocommit = OFF;

أسلوب قواعد بيانات MySQL / Oracle / SQLite

BEGIN;
-- Statements
COMMIT;
BEGIN; -- Statements COMMIT;

أسلوب قواعد بيانات SQL Server / ACCESS

BEGIN TRANSACTION;
-- Statements
COMMIT;
BEGIN TRANSACTION; -- Statements COMMIT;

خطوات بناء Transaction

  1. نضع الأمر BEGIN أو BEGIN TRANSACTION على حسب نوع قاعدة البيانات التي نستخدمها.
  2. نضع الأوامر التي نريدها إما أن تتنفذ جميعها بنجاح و إما لا يتم تنفيذها.
  3. نضع الأمر COMMIT لحفظ جميع التغييرات إذا تم تنفيذ جميع الأوامر بنجاح.

في الإستعلام التالي إفترضنا أننا نقوم بتخزين عملية شراء لمنتج.

  • المنتج الذي تم بيعه إفترضنا أنه يملك id يساوي 4.
  • الشخص الذي قام بشراء المنتج إفترضنا أنه يملك id يساوي 1.

إذا تمت عملية البيع بنجاح، يجب إنقاص كمية المنتج الذي تم بيعه في جدول المنتجات products.
أيضاً، يجب إضافة id الشخص الذي قام بالشراء و id المنتج الذي تم بيعه في جدول الطلبيات orders.

بما أنه يجب تنفيذ العمليتين سويةً أو عدم تنفيذهما من الأساس في حال حدث خطأ ما، سنقوم بوضع العملية بداخل Transaction.

مثال

-- Transaction هنا قمنا ببدء
BEGIN;
-- 4 يساوي id يساوي 1 إشترى 10 قطع من المنتج الذي يملك id هنا إفترضنا أن المستخدم الذي يملك
INSERT INTO orders (user_id, product_id, quantity, sale_date) values (1, 4, 10, '2024-07-11');
-- يساوي 1 بهدف إنقاص 10 منها id للمنتج الذي يملك available هنا إفترضنا أننا نريد تحديث قيمة الحقل
UPDATE products SET available = 76 WHERE id = 1;
-- سيتم حفظ التغيرات في قاعدة البيانات Transaction إذا لم يحدث أي خطأ في الأوامر الموضوعة في الـ
COMMIT;
-- Transaction هنا قمنا ببدء BEGIN; -- 4 يساوي id يساوي 1 إشترى 10 قطع من المنتج الذي يملك id هنا إفترضنا أن المستخدم الذي يملك INSERT INTO orders (user_id, product_id, quantity, sale_date) values (1, 4, 10, '2024-07-11'); -- يساوي 1 بهدف إنقاص 10 منها id للمنتج الذي يملك available هنا إفترضنا أننا نريد تحديث قيمة الحقل UPDATE products SET available = 76 WHERE id = 1; -- سيتم حفظ التغيرات في قاعدة البيانات Transaction إذا لم يحدث أي خطأ في الأوامر الموضوعة في الـ COMMIT;

النتيجة

0 row(s) affected
1 row(s) inserted
1 row(s) affected
0 row(s) affected

النتيجة تعني أنه تم تنفيذ الأوامر BEGIN و INSERT و UPDATE و COMMIT بنجاح.

إذا قمت بعرض بيانات الجدول products ستلاحظ أنه تم تحديث قيمة الحقل quantity حيث كانت 86 ثم أصبحت 76.

products
id title available
1 Mouse 76
2 Keyboard 140
3 Printer 45
4 Screen 32
5 Chair 80

و إذا قمت بعرض بيانات الجدول orders ستلاحظ أنه تم إضافة سطر جديد فيه كما يلي.

orders
user_id product_id quantity sale_date
1 4 10 2024-07-11

التراجع عن تنفيذ أوامر الـ Transaction

لحفظ كل التغيرات التي تم إجراءها بداخل Transaction قلنا أنه يجب تنفيذ الأمر COMMIT.
الآن للتراجع عن كل التغيرات التي تم إجراءها في قاعدة البيانات (أي لعدم حفظها)، يمكن تنفيذ الأمر ROLLBACK ما لم يتم تنفيذ الأمر COMMIT بعد لأنه لا يمكننا التراجع عن تنفيذ الأوامر في حال سبق و تم حفظها.


في الإستعلام التالي إفترضنا أننا نقوم بتخزين عملية شراء لمنتج و لكننا في النهاية قررنا إلغاء العملية.

  • المنتج الذي تم بيعه إفترضنا أنه يملك id يساوي 5.
  • الشخص الذي قام بشراء المنتج إفترضنا أنه يملك id يساوي 2.

إذا تمت عملية البيع بنجاح، يجب إنقاص كمية المنتج الذي تم بيعه في جدول المنتجات products.
أيضاً، يجب إضافة id الشخص الذي قام بالشراء و id المنتج الذي تم بيعه في جدول الطلبيات orders.

بما أنه يجب تنفيذ العمليتين سويةً أو عدم تنفيذهما من الأساس في حال حدث خطأ ما، سنقوم بوضع العملية بداخل Transaction.
في النهاية، بما أننا سنقوم بإلغاء تنفيذ العمليتين فإننا سنستدعي الأمر ROLLBACK.

مثال

-- Transaction هنا قمنا ببدء
BEGIN;
-- 5 يساوي id يساوي 2 بهدف إشترى 30 قطعة من المنتج الذي يملك id هنا إفترضنا أن المستخدم الذي يملك
INSERT INTO orders (user_id, product_id, quantity, sale_date) values (5, 2, 30, '2024-07-11');
-- يساوي 5 بهدف إنقاص 30 منها id للمنتج الذي يملك available هنا إفترضنا أننا نريد تحديث قيمة الحقل
UPDATE products SET available = 50 WHERE id = 5;
-- INSERT و UPDATE للتراجع عن تنفيذ الأمرين ROLLBACK هنا قمنا باستدعاء الأمر
ROLLBACK;
-- Transaction هنا قمنا ببدء BEGIN; -- 5 يساوي id يساوي 2 بهدف إشترى 30 قطعة من المنتج الذي يملك id هنا إفترضنا أن المستخدم الذي يملك INSERT INTO orders (user_id, product_id, quantity, sale_date) values (5, 2, 30, '2024-07-11'); -- يساوي 5 بهدف إنقاص 30 منها id للمنتج الذي يملك available هنا إفترضنا أننا نريد تحديث قيمة الحقل UPDATE products SET available = 50 WHERE id = 5; -- INSERT و UPDATE للتراجع عن تنفيذ الأمرين ROLLBACK هنا قمنا باستدعاء الأمر ROLLBACK;

النتيجة

0 row(s) affected
1 row(s) inserted
1 row(s) affected
0 row(s) affected

النتيجة تعني أنه تم تنفيذ الأوامر BEGIN و INSERT و UPDATE و ROLLBACK بنجاح.

إذا قمت بعرض بيانات الجدول products ستلاحظ أنها لم تتغير.

products
id title available
1 Mouse 76
2 Keyboard 140
3 Printer 45
4 Screen 32
5 Chair 80

و إذا قمت بعرض بيانات الجدول orders ستلاحظ أنه لم تتغير أيضاُ.

orders
user_id product_id quantity sale_date
1 4 10 2024-07-11