Tranzaksiya β€” bir guruh amallar birgalikda muvaffaqiyatli yoki umuman bajarilmaydi.

ACID xususiyatlari

  • Atomicity β€” ya hammasi, ya hech narsa
  • Consistency β€” ma'lumot har doim to'g'ri holatda
  • Isolation β€” tranzaksiyalar bir-biriga ta'sir qilmaydi
  • Durability β€” commit qilingan ma'lumot yo'qolmaydi

Tranzaksiya sintaksisi

BEGIN;  -- yoki START TRANSACTION;

UPDATE hisoblar SET balans = balans - 500000 WHERE id = 1;
UPDATE hisoblar SET balans = balans + 500000 WHERE id = 2;

COMMIT; -- Ikkala o'zgarish saqlanadi

ROLLBACK β€” bekor qilish

BEGIN;

UPDATE hisoblar SET balans = balans - 500000 WHERE id = 1;

-- Xato bo'ldi!
ROLLBACK; -- Hamma narsa asl holiga qaytadi

SAVEPOINT

BEGIN;

INSERT INTO buyurtmalar VALUES (1, 'Python kursi', 500000);
SAVEPOINT birinchi_bosqich;

INSERT INTO to'lovlar VALUES (1, 500000, NOW());
-- Bu o'zgarishni bekor qilish
ROLLBACK TO birinchi_bosqich;

-- Buyurtma saqlanadi, to'lov yo'q
COMMIT;

Izolyatsiya darajalari

-- Read Committed (default PostgreSQL)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- Serializable (eng yuqori himoya)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Read Uncommitted (eng past himoya)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

Amaliy misol: Bank o'tkazmasi

CREATE OR REPLACE FUNCTION pul_o'tkaz(
    yuboruvchi_id INT,
    qabul_qiluvchi_id INT,
    miqdor DECIMAL
) RETURNS VOID AS $$
BEGIN
    -- Balansni tekshirish
    IF (SELECT balans FROM hisoblar WHERE id = yuboruvchi_id) < miqdor THEN
        RAISE EXCEPTION 'Balans yetarli emas';
    END IF;

    UPDATE hisoblar SET balans = balans - miqdor WHERE id = yuboruvchi_id;
    UPDATE hisoblar SET balans = balans + miqdor WHERE id = qabul_qiluvchi_id;

    INSERT INTO tarixi (yuboruvchi, qabul_qiluvchi, miqdor, vaqt)
    VALUES (yuboruvchi_id, qabul_qiluvchi_id, miqdor, NOW());
END;
$$ LANGUAGE plpgsql;