WisarWisar
Dasturlash kitobi/6-QISM — Database19 daqiqa

6.9-bob: Normalizatsiya (1NF–3NF), tranzaksiyalar (ACID), izolyatsiya darajalari

6-QISM — Ma'lumotlar bazasi (Database) · 9-mavzu


1. Kirish va motivatsiya

SQL'ni amaliy va ekspert darajada (6.4–6.8) o'rgandik. Endi relatsion DB'ning ilmiy/nazariy asoslariga — DB dizaynining poydevoriga — o'tamiz: normalizatsiya (ma'lumotni to'g'ri tashkil qilish) va tranzaksiyalar (ACID) + izolyatsiya darajalari (parallel ishlashda yaxlitlik). Bu mavzu — "DB'ni shunchaki ishlataman" bilan "DB'ni to'g'ri loyihalayman" o'rtasidagi farq. Intervyularda ham, real loyihada ham — eng muhim bilimlardan.

Normalizatsiya — ma'lumotni jadvallarga to'g'ri bo'lish qoidalari (1NF, 2NF, 3NF). Maqsad — takrorni yo'qotish va anomaliyalarni (yangilash/o'chirish/qo'shish muammolari) oldini olish. Noto'g'ri loyihalangan DB — ma'lumot takrorlanadi, bir joyda yangilanib boshqasida qolib ketadi (nomuvofiqlik), va keyinroq tuzatish — qiyin/qimmat. Normalizatsiya — bu muammolarni boshidanoq oldini oladi.

Tranzaksiya va izolyatsiya — bir nechta foydalanuvchi/so'rov bir vaqtda DB'ni o'zgartirganda yaxlitlikni saqlash. 6.1 2.11-bob da ACID'ni qisqacha ko'rdik; 6.5/6.6 da tranzaksiyani ishlatdik. Endi chuqur: ACID'ning har harfi, izolyatsiya darajalari (parallel anomaliyalar — dirty read, phantom), va qaysisini qachon tanlash. Bank, to'lov, buyurtma — bularsiz xato (pul yo'qolishi, ikki marta sotish) muqarrar.

O'xshatish 1 (normalizatsiya): ma'lumotni takrorlash — har xonada alohida telefon kitobi (raqam o'zgarsa, hammasini yangilash kerak — biri qolib ketadi). Normalizatsiya — bitta markaziy telefon kitobi + har xonada unga ishora (raqam bir joyda; o'zgarsa, bir joyda). Takror yo'q, nomuvofiqlik yo'q.

O'xshatish 2 (izolyatsiya): ikki kassir bir vaqtda oxirgi bitta mahsulotni sotmoqchi. Izolyatsiyasiz — ikkalasi ham "bor" deb ko'radi, ikkalasi ham sotadi (xato — bitta mahsulot ikki marta!). Izolyatsiya — "navbat"/"qulf" bilan buni oldini oladi (biri sotsa, ikkinchisi "tugadi" ko'radi).

Nega muhim?

  • DB dizayni poydevori — normalizatsiya to'g'ri loyihalashning asosi.
  • Yaxlitlik — ACID/izolyatsiya bank/to'lovda hayotiy (xato qimmat).
  • Parallel muammolar — race condition, dirty read — real va xavfli.
  • Intervyu/ekspertlik — bu nazariya backend dasturchining majburiy bilimi.

2. Nazariya — chuqur tushuntirish

2.1. Nega normalizatsiya (takror muammolari)

Normalizatsiyasiz (bitta katta jadval) muammolar:

text
  Yomon dizayn (bitta jadval — takror):
  | buyurtma | mijoz_ism | mijoz_tel    | mahsulot | narx  |
  | 1        | Ali       | +998901112233| Olma     | 12000 |
  | 2        | Ali       | +998901112233| Banan    | 18000 |    Ali ma'lumoti TAKROR

  Anomaliyalar:
   Update anomaliyasi: Ali tel o'zgarsa  HAR qatorni yangilash (biri qolsa — nomuvofiq)
   Delete anomaliyasi: oxirgi buyurtma o'chsa  Ali ma'lumoti ham yo'qoladi
   Insert anomaliyasi: buyurtmasiz mijoz qo'shib bo'lmaydi (buyurtma kerak)

Normalizatsiya — bu anomaliyalarni takrorni yo'qotib hal qiladi (ma'lumotni bo'lib, bog'lab — 6.1: 2.10). Har fakt — bir joyda. Bu — relatsion dizaynning asosiy maqsadi.

2.2. Funksional bog'liqlik (functional dependency)

Normalizatsiya funksional bog'liqlikka asoslanadi: bir ustun boshqasini aniqlaydi:

text
  user_id  ism, email      (user_id ni bilsangiz, ism/email aniq)
  X  Y    "X Y ni aniqlaydi" (X o'zgarsa, Y aniq)

  Maqsad: har ustun PRIMARY KEY'ga to'liq bog'liq bo'lsin (boshqasiga emas)

Bu — normalizatsiyaning matematik asosi. "Bu ustun nimaga bog'liq?" — agar PK'ga emas, boshqa ustunga bog'liq bo'lsa — muammo (2NF/3NF buziladi). Hozircha amaliy qoidalarni ko'ramiz.

2.3. 1NF (Birinchi normal forma) — atomik qiymatlar

1NF: har katak atomik (bo'linmas) qiymat; takrorlanuvchi guruh yo'q:

text
   1NF buzilgan (bir katakda ko'p qiymat):
  | id | ism | telefonlar              |
  | 1  | Ali | +99890111, +99890222    |    bir katakda ikkita (atomik emas!)

   1NF (atomik):
  users: | id | ism |       phones: | user_id | raqam     |
         | 1  | Ali |               | 1       | +99890111 |
                                    | 1       | +99890222 |

1NF qoidasi: bir katak — bitta qiymat (vergul bilan ro'yxat emas, massiv emas). Takrorlanuvchi ustunlar (telefon1, telefon2, telefon3) ham — 1NF buzilishi. Yechim: alohida jadval (one-to-many — 6.1).

2.4. 2NF (Ikkinchi normal forma) — to'liq bog'liqlik

2NF: 1NF + har ustun butun primary keyga bog'liq (qisman emas — digitalocean):

text
  Faqat COMPOSITE PK (ko'p ustunli PK) bo'lganda dolzarb.

   2NF buzilgan (PK = order_id + product_id):
  | order_id | product_id | miqdor | mahsulot_nomi |
   mahsulot_nomi faqat product_id'ga bog'liq (butun PK'ga emas — qisman!)

   2NF (qisman bog'liqlikni ajratish):
  order_items: | order_id | product_id | miqdor |
  products:    | product_id | mahsulot_nomi |    alohida

2NF qoidasi: agar PK bir necha ustundan iborat bo'lsa (composite), har ustun butun PK'ga bog'liq bo'lishi kerak (faqat bir qismiga emas). mahsulot_nomi faqat product_idga bog'liq — uni alohida jadvalga. Yagona ustunli PK'da 2NF avtomatik (qisman bog'liqlik bo'lolmaydi).

2.5. 3NF (Uchinchi normal forma) — tranzitiv bog'liqlik yo'q

3NF: 2NF + tranzitiv bog'liqlik yo'q (ustun boshqa PK bo'lmagan ustunga bog'liq emas — freecodecamp):

text
   3NF buzilgan (tranzitiv):
  | user_id | ism | shahar_id | shahar_nomi | shahar_aholisi |
   shahar_nomi/aholisi shahar_id'ga bog'liq (user_id'ga EMAS — tranzitiv!)
     user_id  shahar_id  shahar_nomi (zanjir)

   3NF (tranzitivni ajratish):
  users:  | user_id | ism | shahar_id |
  cities: | shahar_id | shahar_nomi | shahar_aholisi |    alohida

3NF qoidasi: PK bo'lmagan ustun boshqa PK bo'lmagan ustunga bog'liq bo'lmasin. shahar_nomiuser_idga emas, shahar_idga bog'liq (tranzitiv zanjir). Uni alohida jadvalga. 3NF — amaliy standart (ko'p loyiha 3NF'da to'xtaydi).

2.6. BCNF va undan yuqori (qisqacha)

text
  BCNF (Boyce-Codd) — 3NF'ning kuchliroq versiyasi (kam holatlarda kerak)
  4NF, 5NF — juda maxsus (ko'p qiymatli bog'liqlik — kamdan-kam)

  Amaliyotda: 3NF (yoki BCNF) YETARLI. Undan yuqori — kamdan-kam.

Amaliy maslahat: 3NF'gacha normalizatsiya qiling — bu standart. BCNF/4NF/5NF — nazariy, maxsus holatlar (akademik). Ko'p real loyiha 3NF'da.

2.7. Denormalizatsiya (ataylab takror — qachon)

Normalizatsiya har doim eng yaxshi emas. Ba'zan ataylab denormalizatsiya (takror) — tezlik uchun (6.1: 2.10):

text
  Normalizatsiya: takror yo'q, lekin ko'p JOIN 6.7-bob — sekinroq o'qish
  Denormalizatsiya: takror bor, lekin JOIN kam — tez o'qish

  Qachon denormalizatsiya:
   O'qish juda ko'p, yozish kam (hisobot, dashboard)
   JOIN juda qimmat (ko'p jadval, katta ma'lumot)
   Hisoblangan qiymat (buyurtma_soni — trigger bilan — 6.8: Misol 7)

Balans: boshlang'ich — normalizatsiya (3NF — toza, ishonchli). Tezlik muammosi paydo bo'lsa — tanlab denormalizatsiya (o'lchab, kerakli joyda). "Premature denormalization" (vaqtidan oldin) — yomon. MongoDB — denormalizatsiyaga moyil (6.3: embed); SQL — normalizatsiyaga.

2.8. Tranzaksiya nima (takrorlash — 6.1: 2.11)

Tranzaksiya — bir nechta amalni bitta bo'linmas birlik sifatida bajarish:

sql
BEGIN;                                            -- boshlash
  UPDATE accounts SET balans = balans - 100 WHERE id = 1;
  UPDATE accounts SET balans = balans + 100 WHERE id = 2;
COMMIT;                                           -- hammasi  saqla (yoki ROLLBACK  bekor)

Tranzaksiya — "hammasi yoki hech narsa" (6.5: 2.9, 6.6: 2.12 da ishlatdik). Pul o'tkazish — ikkala UPDATE yoki hech biri. Bu — ACIDning amaliy ko'rinishi.

2.9. ACID — har harf chuqur

text
  A — Atomicity (atomiklik):
      tranzaksiya bo'linmas — HAMMASI yoki HECH NARSA (yarim bajarilmaydi)
      pul yechildi, lekin qo'shilmadi  ROLLBACK (ikkalasi bekor)

  C — Consistency (izchillik):
      tranzaksiya DB'ni bir TO'G'RI holatdan boshqa TO'G'RI holatga o'tkazadi
      (constraint, FK, CHECK — 6.4 — buzilmaydi)

  I — Isolation (izolyatsiya):
      parallel tranzaksiyalar bir-biriga XALAQIT bermaydi 2.11-bob
      (ikki kassir muammosi — o'xshatish 2)

  D — Durability (doimiylik):
      COMMIT bo'lgan ma'lumot YO'QOLMAYDI (server o'chsa ham — diskda)

ACID — relatsion DB'ning kafolati (6.1: 2.11). Eng murakkabi — Isolation (parallel ishlash — 2.10-2.14). Atomicity/Durability — DB avtomatik; Consistency — constraint'lar bilan; Isolation — daraja tanlash bilan.

2.10. Parallel muammolar (read phenomena)

Ko'p tranzaksiya bir vaqtda ishlaganda muammolar (anomaliyalar):

text
  Dirty read (iflos o'qish):
  T1 o'zgartirdi (hali COMMIT qilmagan)  T2 shu o'zgarishni o'qidi 
  T1 ROLLBACK qildi  T2 mavjud bo'lmagan ma'lumotni o'qidi (xato!)

  Non-repeatable read (takrorlanmas o'qish):
  T1 qatorni o'qidi  T2 uni o'zgartirib COMMIT qildi 
  T1 yana o'qidi  BOSHQA qiymat (bir tranzaksiyada ikki xil natija)

  Phantom read (arvoh o'qish):
  T1 "yosh>18" so'rovini bajardi (10 qator)  T2 yangi qator qo'shdi 
  T1 yana bajardi  11 qator (yangi "arvoh" qator paydo bo'ldi)

  Lost update (yo'qolgan yangilanish):
  T1 va T2 bir qatorni o'qidi  ikkalasi o'zgartirib yozdi  biri yo'qoldi

Bu anomaliyalar — real va xavfli (5.1: race condition, 5.18: OTP). Izolyatsiya darajasi — qaysi anomaliyalardan himoya qilishni belgilaydi (yuqori daraja = ko'proq himoya, lekin sekinroq — 2.11).

2.11. Izolyatsiya darajalari (4 ta)

SQL standarti 4 izolyatsiya darajasini belgilaydi (past yuqori himoya):

text
  ┌─────────────────┬───────────┬──────────────────┬──────────┐
  │ Daraja          │ Dirty read│ Non-repeatable   │ Phantom  │
  ├─────────────────┼───────────┼──────────────────┼──────────┤
  │ READ UNCOMMITTED│  mumkin │  mumkin        │  mumkin│
  │ READ COMMITTED  │  yo'q   │  mumkin        │  mumkin│   default (PostgreSQL)
  │ REPEATABLE READ │  yo'q   │  yo'q          │ /*   │   default (MySQL)
  │ SERIALIZABLE    │  yo'q   │  yo'q          │  yo'q  │   eng kuchli
  └─────────────────┴───────────┴──────────────────┴──────────┘
  *PostgreSQL REPEATABLE READ phantom'ni ham oldini oladi

Balans: yuqori daraja = ko'proq himoya, lekin sekinroq (ko'proq qulf/tekshiruv). READ COMMITTED (PostgreSQL default) — ko'p ilova uchun yetarli. SERIALIZABLE — eng xavfsiz (tranzaksiyalar ketma-ket bo'lgandek), lekin sekin (bank, kritik). Kerakli darajani tanlang.

2.12. Izolyatsiya darajasini sozlash

sql
-- Tranzaksiya uchun daraja
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  -- ... amallar ...
COMMIT;

-- yoki sessiya darajasida
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Ko'p loyihada default (READ COMMITTED) yetadi. Kritik amal (pul, zaxira) — yuqoriroq (REPEATABLE READ/SERIALIZABLE). Lekin yuqori daraja — serialization xatosi (konflikt) berishi mumkin tranzaksiyani qayta urinish kerak 2.14-bob.

2.13. Lock (qulf) — pessimistik vs optimistik

Parallel muammolarni hal qilishning ikki yondashuvi:

text
  PESSIMISTIK lock (qulflash):
  "Men o'zgartiraman, boshqalar kutsin"  qatorni QULFLAYDI
  SELECT ... FOR UPDATE;   -- qatorni qulflab o'qish (boshqalar kutadi)
   Konflikt yo'q;  sekin (kutish), deadlock xavfi

  OPTIMISTIK lock (versiya):
  "O'zgartiraman, lekin yozishda tekshiraman"  version ustuni
  UPDATE ... WHERE id = 1 AND version = 5;   -- version o'zgargan bo'lsa, yangilamaydi
   Tez (qulf yo'q);  konflikt bo'lsa, qayta urinish

Pessimistik (FOR UPDATE) — kam konflikt, qisqa tranzaksiya (zaxira kamaytirish). Optimistik (version) — ko'p o'qish, kam konflikt (ko'p foydalanuvchi profil tahrirlaydi). Tanlov — konflikt ehtimoliga qarab.

MVCC (Multi-Version Concurrency Control): PostgreSQL (va MySQL InnoDB) qulfning o'rniga ko'pincha shu mexanizmni ishlatadi — har tranzaksiya ma'lumotning o'z snapshotini (bir lahzadagi versiyasini) ko'radi. UPDATE eski qatorni o'chirmaydi, balki yangi versiya yozadi; eski o'qigan tranzaksiya hali ham eski versiyani ko'radi. Natijada o'quvchilar yozuvchilarni, yozuvchilar o'quvchilarni bloklamaydi — shuning uchun SELECT odatda qulf kutmaydi. REPEATABLE READ 2.11-bob shu snapshot ustiga quriladi. Kamchiligi — eski versiyalarni tozalash kerak (PostgreSQL'da VACUUM).

2.14. Deadlock va qayta urinish

Deadlock — ikki tranzaksiya bir-birini kutib qoladi (T1 A'ni qulfladi, B'ni kutadi; T2 B'ni qulfladi, A'ni kutadi):

text
  T1: lock A  B kutadi
  T2: lock B  A kutadi
   ikkalasi bir-birini kutadi (deadlock!)

  DB buni ANIQLAYDI va birini bekor qiladi (deadlock victim) 
  ilova shu tranzaksiyani QAYTA urinishi kerak

Yechim: (1) qulflarni bir tartibda olish (A, keyin B — har doim); (2) tranzaksiyani qisqa tutish; (3) deadlock/serialization xatosida qayta urinish (retry — 5.22 ruhida). Bank/yuqori yukli tizimda muhim.

2.15. Node.js'da tranzaksiya + retry

js
// Tranzaksiya + serialization xatosida qayta urinish (2.12, 2.14)
async function tranzaksiyaRetry(fn, urinish = 3) {
  for (let i = 0; i < urinish; i++) {
    const client = await pool.connect();
    try {
      await client.query("BEGIN ISOLATION LEVEL SERIALIZABLE");
      const natija = await fn(client);
      await client.query("COMMIT");
      return natija;
    } catch (err) {
      await client.query("ROLLBACK");
      if (err.code === "40001" && i < urinish - 1) continue;   // serialization_failure  retry
      throw err;
    } finally {
      client.release();                                         // (6.5: 2.10)
    }
  }
}

Yuqori izolyatsiya (SERIALIZABLE) — konflikt (40001) berishi mumkin qayta urinish (idempotent — 5.22: 2.13). Bu — kritik tizimlarda standart naqsh.

2.16. Best practices (14)

text
   3NF'gacha normalizatsiya (toza dizayn — 2.5); tanlab denormalizatsiya (o'lchab — 2.7)
   Tranzaksiya muhim amalda (pul, zaxira — atomik — 2.8)
   Tranzaksiyani QISQA tuting (uzun  lock, deadlock — 2.14)
   To'g'ri izolyatsiya darajasi (default odatda yetadi; kritik — yuqori — 2.11)
   Deadlock/serialization  qayta urinish (2.14, 2.15)
   FOR UPDATE (pessimistik) yoki version (optimistik) — konfliktga qarab 2.13-bob
   Constraint'lar (consistency — FK/CHECK — 6.4) bilan yaxlitlik

3. Sintaksis / qoidalar — tez ma'lumotnoma

text
  NORMALIZATSIYA:
  1NF — atomik qiymat (bir katak, bir qiymat — 2.3)
  2NF — 1NF + butun PK'ga bog'liqlik (qisman emas — 2.4)
  3NF — 2NF + tranzitiv bog'liqlik yo'q 2.5-bob

  ACID 2.9-bob: Atomicity, Consistency, Isolation, Durability

  IZOLYATSIYA 2.11-bob: READ UNCOMMITTED < READ COMMITTED < REPEATABLE READ < SERIALIZABLE
sql
BEGIN [ISOLATION LEVEL ...]; ... COMMIT/ROLLBACK;   -- tranzaksiya (2.8, 2.12)
SELECT ... FOR UPDATE;                                -- pessimistik lock (2.13)
UPDATE ... WHERE id=? AND version=?;                 -- optimistik (2.13)

4. Batafsil misollar

Misol 1 — Normalizatsiya bosqichlari (2.3-2.5)

text
  Boshlang'ich (normalizatsiyasiz — 2.1):
  | buyurtma_id | mijoz | tel        | mahsulotlar      | shahar    | shahar_kod |
  | 1           | Ali   | +99890111  | Olma, Banan      | Toshkent  | 100        |

  1NF (atomik — mahsulotlarni ajrating — 2.3):
  order_items: | buyurtma_id | mahsulot |
               | 1           | Olma     |
               | 1           | Banan    |

  2NF (qisman bog'liqlikni ajrating — 2.4):
  (composite PK bo'lsa — mahsulot tafsilotini alohida)

  3NF (tranzitivni ajrating — shahar — 2.5):
  orders: | id | mijoz_id |        cities: | id | shahar | kod |
  users:  | id | ism | tel | shahar_id |
   har fakt bir joyda (takror yo'q)

Misol 2 — 3NF schema (toza dizayn — 2.5)

sql
-- 3NF'ga mos schema (har jadval — bir mavzu, takror yo'q)
CREATE TABLE cities (
  id SERIAL PRIMARY KEY, nom VARCHAR(50), kod VARCHAR(10)
);
CREATE TABLE users (
  id SERIAL PRIMARY KEY, ism VARCHAR(50), tel VARCHAR(20),
  city_id INTEGER REFERENCES cities(id)            -- shaharga ishora (3NF — 2.5)
);
CREATE TABLE orders (
  id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), created_at TIMESTAMPTZ
);
CREATE TABLE order_items (
  order_id INTEGER REFERENCES orders(id),
  product_id INTEGER REFERENCES products(id),
  miqdor INTEGER, narx DECIMAL(10,2),              -- narx — snapshot (6.3: Misol 7)
  PRIMARY KEY (order_id, product_id)               -- composite PK
);
-- Har fakt bir joyda; bog'lanish FK bilan (6.4: 2.6)

Misol 3 — Tranzaksiya (pul o'tkazish — atomik — 2.8, 2.9)

js
// Atomik pul o'tkazish (6.6: 2.12 ga o'xshash)
export async function pulOtkaz(fromId, toId, summa) {
  const client = await pool.connect();
  try {
    await client.query("BEGIN");                   // tranzaksiya (2.8)

    // Atomic: yechish (balans yetarli bo'lsa)
    const { rowCount } = await client.query(
      "UPDATE accounts SET balans = balans - $1 WHERE id = $2 AND balans >= $1",
      [summa, fromId]
    );
    if (rowCount === 0) throw new Error("Balans yetarli emas");   //  ROLLBACK

    await client.query("UPDATE accounts SET balans = balans + $1 WHERE id = $2", [summa, toId]);
    await client.query("INSERT INTO transfers (from_id, to_id, summa) VALUES ($1,$2,$3)",
      [fromId, toId, summa]);

    await client.query("COMMIT");                  // hammasi  saqla (Atomicity — 2.9)
  } catch (err) {
    await client.query("ROLLBACK");                // xato  BEKOR (yarim o'tkazish yo'q)
    throw err;
  } finally {
    client.release();                              // (6.5: 2.10)
  }
}

Misol 4 — Pessimistik lock (zaxira — 2.13)

js
// Mahsulot zaxirasini xavfsiz kamaytirish (race condition'siz — 2.10, 2.13)
export async function zaxiraKamaytir(productId, miqdor) {
  const client = await pool.connect();
  try {
    await client.query("BEGIN");

    // FOR UPDATE — qatorni QULFLAB o'qish (boshqa tranzaksiyalar kutadi — 2.13)
    const { rows } = await client.query(
      "SELECT zaxira FROM products WHERE id = $1 FOR UPDATE", [productId]
    );
    if (rows[0].zaxira < miqdor) throw new Error("Zaxira yetarli emas");

    await client.query("UPDATE products SET zaxira = zaxira - $1 WHERE id = $2",
      [miqdor, productId]);
    await client.query("COMMIT");
  } catch (err) {
    await client.query("ROLLBACK");
    throw err;
  } finally {
    client.release();
  }
}
// FOR UPDATE'siz: ikki so'rov bir vaqtda "zaxira bor" deb ko'rib, ikkalasi sotardi (xato — 2.10)

Misol 5 — Optimistik lock (version — 2.13)

js
// Optimistik lock (version ustuni — 2.13)
// users jadvalida: version INTEGER DEFAULT 0
export async function profilYangila(id, data, version) {
  const { rowCount } = await pool.query(
    `UPDATE users SET ism = $1, version = version + 1
     WHERE id = $2 AND version = $3`,             // version mos bo'lsa (2.13)
    [data.ism, id, version]
  );
  if (rowCount === 0) {
    throw new Error("Ma'lumot boshqa joyda o'zgargan — qayta yuklang");   // konflikt
  }
}
// Ikki foydalanuvchi bir profilni tahrirlasa, ikkinchisining version eskirgan  konflikt

Misol 6 — Izolyatsiya + retry (kritik — 2.15)

js
// SERIALIZABLE + qayta urinish (eng xavfsiz, kritik amal — 2.15)
export async function kritikAmal(fn) {
  for (let i = 0; i < 3; i++) {
    const client = await pool.connect();
    try {
      await client.query("BEGIN ISOLATION LEVEL SERIALIZABLE");   // eng kuchli (2.11)
      const natija = await fn(client);
      await client.query("COMMIT");
      return natija;
    } catch (err) {
      await client.query("ROLLBACK");
      if (err.code === "40001" && i < 2) {                        // serialization konflikti
        await new Promise(r => setTimeout(r, 50 * (i + 1)));      // kichik kutish
        continue;                                                 // qayta urin (2.14)
      }
      throw err;
    } finally {
      client.release();
    }
  }
}

5. To'g'ri va noto'g'ri holatlar

1) Takrorli (normalizatsiyasiz) dizayn

text
 bitta katta jadval, ma'lumot takror (anomaliyalar — 2.1)
 3NF — har fakt bir joyda, FK bilan bog'langan (2.5)

2) Bir katakda ko'p qiymat (1NF buzilishi)

sql
--  telefonlar VARCHAR "raqam1, raqam2" (atomik emas — 2.3)
--  alohida phones jadvali (one-to-many)

3) Tranzaksiyasiz pul o'tkazish

js
//  ikki alohida UPDATE (orasida xato  yarim o'tkazish — 2.8)
await q("UPDATE ... balans - 100"); await q("UPDATE ... balans + 100");

//  tranzaksiya (atomik)
BEGIN; ...; COMMIT;

4) Race condition (lock'siz zaxira)

js
//  o'qib, keyin yangilash (orasida boshqa so'rov — 2.10)
const z = await q("SELECT zaxira ..."); if (z > 0) await q("UPDATE zaxira - 1");

//  FOR UPDATE yoki atomik UPDATE WHERE zaxira >= miqdor (2.13)

5) Uzun tranzaksiya

text
 tranzaksiya ichida sekin ish (tashqi API, kutish)  lock uzoq, deadlock (2.14)
 tranzaksiyani qisqa tuting (faqat DB amallari)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Ma'lumot nomuvofiq (bir joyda yangilangan, boshqada eski)

Sababi: takror (normalizatsiyasiz — 2.1). Yechimi: 3NF; ma'lumot bir joyda; FK.

Xato 2 — deadlock detected (40P01)

Sababi: ikki tranzaksiya bir-birini kutadi 2.14-bob. Yechimi: qulflarni bir tartibda; qisqa tranzaksiya; qayta urinish.

Xato 3 — could not serialize access (40001)

Sababi: SERIALIZABLE konflikti 2.12-bob. Yechimi: qayta urinish (Misol 6, 2.15).

Xato 4 — Yo'qolgan yangilanish (lost update)

Sababi: ikki tranzaksiya bir qatorni yozdi 2.10-bob. Yechimi: FOR UPDATE (pessimistik) yoki version (optimistik — 2.13).

Xato 5 — Juda normalizatsiya (ko'p JOIN, sekin)

Sababi: o'qish ko'p, JOIN qimmat 2.7-bob. Yechimi: tanlab denormalizatsiya; materialized view 6.8-bob; kesh 5.21-bob.

Xato 6 — Tranzaksiya ROLLBACK qilinmadi (xatoda)

Sababi: catch'da ROLLBACK yo'q. Yechimi: try/catch/finally; xatoda ROLLBACK, doim release.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • DB asoslari 6.1-bob: ACID, relatsion model.
  • SQL/JOIN (6.4, 6.7): normalizatsiya — JOIN sababi.
  • Tranzaksiya (6.5, 6.6): ishlatish; bu yerda chuqur.
  • Race condition 5.1-bob: parallel muammolar.
  • Redis 5.21-bob: denormalizatsiya muqobili (kesh).
  • Trigger 6.8-bob: denormalizatsiya maydonini saqlash.
  • Query optimization 6.10-bob: denormalizatsiya/indeks.
  • ER modeling 6.17-bob: normalizatsiya — dizayn.
  • Idempotentlik 5.22-bob: retry bilan.
  • Xavfsizlik (14): yaxlitlik (pul).

8. Eng yaxshi amaliyotlar (best practices)

  • 3NF'gacha normalizatsiya (toza, anomaliyasiz — 2.5); tanlab denormalizatsiya (o'lchab — 2.7).
  • 1NF: atomik qiymat (massiv/ro'yxat katakda emas — 2.3).
  • Tranzaksiya muhim amalda (pul/zaxira — atomik — 2.8).
  • Tranzaksiyani qisqa tuting (lock/deadlock — 2.14).
  • To'g'ri izolyatsiya (default odatda yetadi; kritik — yuqori — 2.11).
  • Race condition: FOR UPDATE yoki version (konfliktga qarab — 2.13).
  • Deadlock/serialization qayta urinish (2.14, 2.15).
  • Constraint'lar bilan consistency (FK/CHECK — 6.4, 2.9).
  • try/catch/finally (ROLLBACK + release — Xato 6).
  • Snapshot (buyurtma narxi — denormalizatsiya — 6.3: Misol 7).

9. Amaliy loyiha: "Normalizatsiyalangan, Tranzaksiyali DB"

DB dizayni va yaxlitlikni mustahkamlash.

Maqsad

3NF schema loyihalash va kritik amallarni tranzaksiya + lock bilan xavfsiz qilish (e-commerce — buyurtma, zaxira, to'lov).

Talablar (requirements)

  1. Normalizatsiya: takrorli dizayndan boshlab, 1NF2NF3NF'ga keltiring (Misol 1, 2.3-2.5).
  2. 3NF schema: users/cities/orders/order_items/products — FK, takror yo'q (Misol 2).
  3. Tranzaksiya: pul o'tkazish yoki buyurtma (atomik — Misol 3, 2.8).
  4. Pessimistik lock: zaxira kamaytirish (FOR UPDATE — Misol 4, 2.13).
  5. Optimistik lock: profil tahrirlash (version — Misol 5, 2.13).
  6. Izolyatsiya + retry: kritik amal (SERIALIZABLE + qayta urinish — Misol 6, 2.15).
  7. Race condition test: lock'siz vs lock bilan farqni ko'rsating 2.10-bob.
  8. Denormalizatsiya tahlili: qaysi joyda kerak — asoslang 2.7-bob.
  9. Deadlock oldini olish: qulf tartibi, qisqa tranzaksiya 2.14-bob.

Maslahatlar (hint)

  • 1NF: atomik (massiv yo'q); 3NF: tranzitiv yo'q (2.3, 2.5).
  • Tranzaksiya: BEGIN/COMMIT/ROLLBACK + finally release (Misol 3, 6-xato).
  • Zaxira: FOR UPDATE yoki UPDATE WHERE zaxira >= miqdor (2.13, 4-holat).
  • Optimistik: version ustuni (Misol 5).
  • SERIALIZABLE: 40001 retry (Misol 6).
  • Tranzaksiya qisqa (deadlock — 2.14).

"Tayyor" mezonlari (acceptance criteria)

  • Normalizatsiya bosqichlari (1NF3NF) ko'rsatilgan.
  • 3NF schema (FK, takror yo'q).
  • Tranzaksiya (atomik, ROLLBACK).
  • Pessimistik lock (FOR UPDATE) zaxirada.
  • Optimistik lock (version) tahrirlashda.
  • Izolyatsiya + retry (kritik).
  • Race condition farqi ko'rsatilgan.
  • Denormalizatsiya qarori asoslangan.
  • Deadlock oldini olish.

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda DB dizayni va yaxlitlik asoslarini chuqur o'rgandik:

  • Normalizatsiya (takror/anomaliyalarni yo'qotish — 2.1): 1NF (atomik — 2.3), 2NF (to'liq bog'liqlik — 2.4), 3NF (tranzitiv yo'q — 2.5); denormalizatsiya (tanlab, tezlik — 2.7).
  • Tranzaksiya (atomik birlik — 2.8); ACID (har harf — 2.9).
  • Parallel muammolar (dirty/non-repeatable/phantom read, lost update — 2.10); izolyatsiya darajalari (4 ta — 2.11, 2.12).
  • Lock (pessimistik FOR UPDATE vs optimistik version — 2.13); deadlock + retry (2.14, 2.15).

Keyingi bob — 6.10-bob: Indekslar va query optimization, EXPLAIN. Toza dizayn (normalizatsiya) va yaxlitlik (ACID)ni bildik; endi tezlikka o'tamiz. Indekslar (chuqur — B-tree, composite, covering, partial), so'rovlarni optimallashtirish, va EXPLAIN (so'rov rejasini ko'rish — sekin so'rovni topish va tuzatish). Bu — production'da DB tezligining kaliti.


Foydalanilgan rasmiy/ishonchli manbalar

  • DigitalOcean / freeCodeCamp — Database Normalization (1NF, 2NF, 3NF, BCNF)
  • PostgreSQL docs — Transaction Isolation; AWS — ACID; izolyatsiya darajalari va anomaliyalar
  • PostgreSQL docs — Explicit Locking (FOR UPDATE), serialization failure

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.9-bob: Normalizatsiya (1NF–3NF), tranzaksiyalar (ACID), izolyatsiya darajalari — Wisar