PostgreSQL / Transaction ба ACID

Transaction ба ACID

Банкны шилжүүлгийг төсөөлөөрэй: таны дансны мөнгийг хасаж, найзынхад нэмнэ. Хэрэв мөнгийг хасчихаад тасалдал гарвал найзынх нэмэгдэхгүй — мөнгө алга болно. Transaction нь энэ асуудлыг шийддэг: бүлэг үйлдлүүдийг нэг нэгж болгон гүйцэтгэж, бүгд амжилттай болох эсвэл бүгдийг цуцлах баталгаа өгдөг.

Transaction үндэс

BEGINCOMMIT хооронд бичигдсэн бүх SQL үйлдэл нэг transaction болно:

sql
-- Жишээ: дансны мөнгө шилжүүлэх
CREATE TABLE accounts (
    id      SERIAL PRIMARY KEY,
    owner   TEXT NOT NULL,
    balance NUMERIC NOT NULL CHECK (balance >= 0)
);

INSERT INTO accounts (owner, balance) VALUES ('Болд', 500000), ('Сарнай', 200000);

-- Transaction эхлүүлэх
BEGIN;

    -- Болдын дансаас хасах
    UPDATE accounts SET balance = balance - 100000 WHERE owner = 'Болд';

    -- Сарнайн данст нэмэх
    UPDATE accounts SET balance = balance + 100000 WHERE owner = 'Сарнай';

-- Бүх үйлдлийг баталгаажуулах
COMMIT;

-- Шалгах
SELECT owner, balance FROM accounts;
-- Болд: 400000 | Сарнай: 300000

COMMIT хийхээс өмнө гаднаас харвал өөрчлөлт харагдахгүй — зөвхөн transaction дотроос харагдана.

ROLLBACK — цуцлах

Ямар нэгэн алдаа гарвал ROLLBACK гүйцэтгэн бүх өөрчлөлтийг буцааж болно:

sql
BEGIN;

    UPDATE accounts SET balance = balance - 999999 WHERE owner = 'Болд';
    -- Болдын дансанд 500000 ₮ л байна, хасалт хэтэрч байна!

    -- Алдаа илрэв, бүхнийг цуцлах
ROLLBACK;

-- Болдын данс хэвээрээ
SELECT balance FROM accounts WHERE owner = 'Болд';
-- 500000

CHECK (balance >= 0) хязгаарлалтаас болж алдаа гарвал PostgreSQL автоматаар transaction-г цуцалдаг. Гэвч алдааг гараар илрүүлж ROLLBACK хийх нь илүү тодорхой код болдог.

SAVEPOINT — дундын цэг

Transaction дотор SAVEPOINT тавьж, бүгдийг биш зарим хэсгийг л цуцлах боломжтой:

sql
BEGIN;

    INSERT INTO accounts (owner, balance) VALUES ('Ганбаяр', 0);
    SAVEPOINT sp_after_insert;

    -- Оролдлого хийх
    UPDATE accounts SET balance = balance + 50000 WHERE owner = 'Ганбаяр';
    SAVEPOINT sp_after_update;

    -- Буруу үйлдэл — зөвхөн энэ хэсгийг цуцал
    UPDATE accounts SET balance = balance - 999999 WHERE owner = 'Ганбаяр';

    -- sp_after_update цэг рүү буцах
    ROLLBACK TO SAVEPOINT sp_after_update;

    -- Ганбаяр 50000-тай хэвээр, бусад үйлдлүүд хэвээр
COMMIT;

SELECT owner, balance FROM accounts WHERE owner = 'Ганбаяр';
-- Ганбаяр: 50000

ACID баталгаа

PostgreSQL нь ACID гэсэн дөрвөн чанарыг бүрэн дэмждэг:

Atomicity (Бүтэн байдал) — Transaction дахь бүх үйлдэл бүгд амжилттай болох эсвэл бүгд цуцлагдана. Хагас дуусаагүй байдал байхгүй.

Consistency (Тогтвортой байдал) — Transaction дуусахад өгөгдлийн сан бүх хязгаарлалт (CHECK, FOREIGN KEY, UNIQUE) -г хангасан хэвээр байна.

Isolation (Тусгаарлалт) — Нэгэн зэрэг гүйцэтгэгдэж буй transaction-ууд бие биедээ нөлөөлөхгүй. Нэг transaction нөгөөгийн дуусаагүй өөрчлөлтийг харахгүй.

Durability (Тогтвортой хадгалалт)COMMIT хийсний дараа тасалдал гарсан ч өгөгдөл алдагдахгүй, дискэнд бүрэн хадгалагдана.

sql
-- Isolation жишээ: нэгэн зэрэг хоёр session ажиллаж байгаа мэт

-- Session 1
BEGIN;
UPDATE accounts SET balance = balance - 50000 WHERE owner = 'Болд';
-- Одоохондоо COMMIT хийгээгүй

-- Session 2 (нэгэн зэрэг)
SELECT balance FROM accounts WHERE owner = 'Болд';
-- Default isolation level дээр: COMMIT хийгдээгүй өөрчлөлт харагдахгүй
-- Үр дүн: 400000 (хуучин утга)

-- Session 1
COMMIT;
-- Одоо Session 2 шинэ утгыг харна: 350000

Дараагийн хичээлд:

Өгөгдлийн санд хэрэглэгч үүсгэж, тэдэнд хүснэгт, view, функцэд эрх олгох болон хасах аргыг сурна.