Transaction — ACID, BEGIN, COMMIT, ROLLBACK, SAVEPOINT

~20 daq · PostgreSQL · Transaction va Concurrency

Bank o'tkazmasi: A hisobdan 100 000 so'm chiqariladi, B hisobga 100 000 so'm qo'shiladi. Birinchi SQL bajarildi — ikkinchisi bajarilishdan oldin server ishdan chiqdi:

UPDATE hisoblar SET balans = balans - 100000 WHERE id = 1; -- bajarildi
-- Server ishdan chiqdi!
UPDATE hisoblar SET balans = balans + 100000 WHERE id = 2; -- bajarilmadi

100 000 so'm yo'qoldi. Transaction — bu ikki SQL yoki ikkalasi bajariladi, yoki hech biri.


ACID

Transaction to'rtta kafolat beradi:

A — Atomicity    — yoki hammasi, yoki hech biri
C — Consistency  — ma'lumot har doim to'g'ri holatda
I — Isolation    — tranzaksiyalar bir-biriga xalaqit bermaydi
D — Durability   — COMMIT dan keyin ma'lumot saqlanadi

BEGIN, COMMIT, ROLLBACK

BEGIN; -- tranzaksiya boshlash

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

COMMIT; -- ikkalasi birda saqlanadi

Xato bo'lsa — bekor qilish:

BEGIN;

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

-- Xato yuz berdi!
ROLLBACK; -- hech narsa o'zgarmaydi, balans qaytariladi

Avtomatik tranzaksiya

Har SQL aslida tranzaksiya ichida bajariladi — PostgreSQL avtomatik BEGIN/COMMIT qo'shadi:

-- Bu ikki so'rov alohida tranzaksiyalar
DELETE FROM eski_qatorlar WHERE id = 1; -- avtomatik COMMIT
DELETE FROM eski_qatorlar WHERE id = 2; -- avtomatik COMMIT

Bir tranzaksiyada bajarish uchun BEGIN ... COMMIT qo'lda yoziladi.


SAVEPOINT — qisman orqaga qaytish

Katta tranzaksiya ichida oraliq nuqta:

BEGIN;

INSERT INTO buyurtmalar (summa) VALUES (50000);
SAVEPOINT birinchi_qism;

INSERT INTO buyurtma_elementlari (nomi) VALUES ('Noutbuk');
-- Bu yerda xato!

ROLLBACK TO SAVEPOINT birinchi_qism;
-- Faqat ikkinchi INSERT bekor — birinchisi saqlanadi

INSERT INTO buyurtma_elementlari (nomi) VALUES ('Telefon');

COMMIT;

Node.js da transaction

const client = await pool.connect();
try {
  await client.query('BEGIN');

  await client.query(
    'UPDATE hisoblar SET balans = balans - $1 WHERE id = $2',
    [100000, 1]
  );
  await client.query(
    'UPDATE hisoblar SET balans = balans + $1 WHERE id = $2',
    [100000, 2]
  );

  await client.query('COMMIT');
} catch (err) {
  await client.query('ROLLBACK');
  throw err;
} finally {
  client.release();
}

Tez-tez uchraydigan xatolar

COMMIT / ROLLBACK unutish:

BEGIN;
UPDATE ...;
-- COMMIT yo'q — session yopilganda avtomatik ROLLBACK
-- Boshqa sessialar bu o'zgarishni ko'rmaydi!

Tranzaksiya ichida uzoq operatsiya:

BEGIN;
-- Ko'p vaqt oluvchi hisoblash...
UPDATE jadval SET ... ; -- Lock ushlab turadi!
COMMIT;

Tranzaksiya qisqa bo'lishi kerak — lock ushlab turish boshqa so'rovlarni bloklaydi.


Xulosa

BEGIN;                              -- tranzaksiya boshlash
  SQL1; SQL2; SQL3;                 -- operatsiyalar
COMMIT;                             -- saqlanadi
-- yoki
ROLLBACK;                           -- bekor qilinadi

SAVEPOINT nom;                      -- oraliq nuqta
ROLLBACK TO SAVEPOINT nom;          -- nuqtaga qaytish
RELEASE SAVEPOINT nom;              -- nuqtani o'chirish

ACID: Atomicity — hammasi yoki hech biri. Durability — COMMIT dan keyin har doim saqlanadi.


Keyingi dars

45-dars: Isolation Levels — Read Committed, Repeatable Read, Serializable