اجعل عمليات الكتابة لديك ذرّية باستخدام المعاملات، وافهم ما تعنيه ضمانات ACID في الممارسة اليومية.
افتح هذا الدرس في Kodokonالتحويل المصرفي هو تعليمتا UPDATE: خصم من حساب، وإضافة إلى الآخر. فإذا فشلت الثانية، تكذب قاعدة البيانات. إن المعاملة تجعل الكتلة غير قابلة للتجزئة، مع ضمانات ACID: A الذرّية (الكل أو لا شيء)، وC الاتساق (تبقى القيود صالحة)، وI العزل (لا ترى المعاملات المتزامنة بعضها منجزًا جزئيًا أبدًا)، وD الديمومة (تصمد عملية COMMIT أمام الأعطال). لهذا الدرس، فضّل عميل sqlite3 الحقيقي: فبعض بيئات الويب التجريبية تؤكّد كل استعلام تلقائيًا.
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
owner TEXT NOT NULL,
balance REAL NOT NULL CHECK (balance >= 0)
);
INSERT INTO accounts (owner, balance)
VALUES
('alice', 500.0),
('bruno', 120.0);الحالة الاسمية: تفتح BEGIN المعاملة، وتتراكم عمليات الكتابة، وتجعلها COMMIT نهائية دفعة واحدة. وفي ما بينهما، لا يرى أي اتصال آخر الحالة الوسيطة (خُصم من alice، ولم يُضَف إلى bruno بعد).
BEGIN;
UPDATE accounts
SET balance = balance - 200
WHERE owner = 'alice';
UPDATE accounts
SET balance = balance + 200
WHERE owner = 'bruno';
COMMIT;
SELECT owner, balance FROM accounts;والآن حالة الفشل. إن خصم 400 من bruno سينتهك CHECK (balance >= 0): فتفشل التعليمة. دقيقة في SQLite: افتراضيًا، يُلغي الخطأ التعليمة المخالفة لكنه يترك المعاملة مفتوحة. ويعود القرار إلى كود تطبيقك: ROLLBACK للتراجع عن كل شيء (وهو رد الفعل السليم)، أو المتابعة إذا كان الخطأ قابلًا للتدارك.
BEGIN;
UPDATE accounts
SET balance = balance - 400
WHERE owner = 'bruno';
-- Error: CHECK (balance >= 0) rejects the row.
ROLLBACK;
SELECT owner, balance FROM accounts;