IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis35/65-dars15 daqiqa
Mundarija (28)

Migratsiya: sxema o'zgarishlarini kod kabi versiyalash

Qisqacha: Migratsiya (migration) — bazaning sxemasini bir holatdan keyingisiga o'tkazadigan, Git'da saqlanadigan raqamli fayl (001_vazifalar.sql, 002_bajarildi.sql). Bazada holat jadvali turadi: qaysi migratsiyalar qo'llangan. Migratsiya vositasi faqat qo'llanmaganlarini, tartib bilan, bir marta bajaradi. Shunda dasturchining noutbukida, testda va prodakshnda sxema bir xil bo'ladi. Qo'llangan fayl hech qachon tahrirlanmaydi — xato yangi migratsiya bilan tuzatiladi.

Bu darsda

  • Migratsiya fayli, holat jadvali va migratsiya tartibi nima ekanini tushuntira olasiz.
  • Oddiy migratsiya mexanizmini SQL'da qo'lda yasab, uning ishlashini ko'rasiz.
  • Nega migratsiya tranzaksiyada bo'lishi kerakligini haqiqiy natijada ko'rasiz.
  • up/down va forward-only yondashuvlarini solishtirasiz.
  • Qo'lda ALTER ning xavfi va "drift" nima ekanini bilasiz.

Oldin bilishingiz kerak: ALTER TABLE va sxemani o'zgartirish, Tranzaksiya asoslari, ORM, query builder va raw SQL, TypeORM.

1. Nega bu kerak?

26-qismda biz vazifalar bazasini SQL fayllar bilan qurdik: 001-jadvallar.sql, 002-tashqi-kalitlar.sql … 014-…. 27-qismda 101 dan 106 gacha qo'shildi. Har safar biz bazani noldan qurdik: bazani o'chiramiz, hamma faylni tartib bilan qo'llaymiz.

O'quv bazasi uchun bu ajoyib. Endi tasavvur qiling: vazifalar-api ishlayapti, bazada 2 000 foydalanuvchining vazifalari bor. Siz 107-…sql yozdingiz. Endi nima qilasiz?

  • Bazani o'chirib noldan qurish — ma'lumot yo'qoladi. Mumkin emas.
  • Faqat 107 ni qo'lda psql bilan qo'llash — mumkin. Lekin: hamkasbingizning noutbukida 107 qo'llanganmi? Test serverida-chi? Kecha Sardor 105 ni qo'lladimi yoki unutdimi?

Uchta muhit, uchta har xil sxema — va hech kim aniq bilmaydi. Bu holat drift (sxemalarning tarqalib ketishi) deyiladi. Uning oqibati — "mening kompyuterimda ishlaydi" xatolari va prodakshnda kutilmagan column does not exist.

O'xshatish: kitob nashriyoti. Muallif kitobni bir necha nashrda tuzatadi. Har nashrning raqami bor, har kutubxona qaysi nashr borligini biladi. Nashrni "ustidan tahrirlash" yo'q — xatoni keyingi nashrda tuzatadi. Migratsiya — sxemaning "nashrlari", holat jadvali — kutubxonaning "qaysi nashr bor" daftari.

2. Migratsiya nima

2.1 Uchta tarkibiy qism

Har qanday migratsiya vositasi (Prisma Migrate, TypeORM, sequelize-cli, node-pg-migrate) uchta g'oyaga qurilgan:

Qism Nima Misol
Migratsiya fayli Bitta o'zgarish: SQL yoki kod 001_vazifalar.sql
Tartib Fayllar qaysi ketma-ketlikda Raqam yoki vaqt belgisi nomda
Holat jadvali Bazada: qaysilari qo'llangan _prisma_migrations, SequelizeMeta

O'tgan ikki darsda ikkita holat jadvalini ko'rdik: TypeORM'ning migrations (timestamp, name) va Sequelize'ning SequelizeMeta (name). Prisma'niki — _prisma_migrations (nom, checksum, boshlangan va tugagan vaqt) — keyingi darsda.

Ishlash tartibi har doim bir xil:

flowchart TD
  A[Koddagi migratsiyalar ro'yxati] --> C{Holat jadvalida bormi?}
  B[(Holat jadvali)] --> C
  C -->|bor| D[O'tkazib yuborish]
  C -->|yo'q| E[Tartib bilan bajarish]
  E --> F[Holat jadvaliga yozish]
  F --> G[Keyingi fayl]

Diagrammadagi asosiy fikr: vosita sxemaning o'zini solishtirmaydi. U faqat holat jadvaliga qaraydi: "bu fayl nomi yozilganmi?". Shuning uchun holat jadvali haqiqatga mos bo'lishi hal qiluvchi.

2.2 Qo'lda yasab ko'ramiz

Mexanizmni tushunish uchun uni vositasiz, toza SQL'da yasaymiz. Bo'sh bazada holat jadvali (biz ishga tushirdik, PostgreSQL 17.6, Windows 11):

sql
CREATE TABLE sxema_migratsiyalari (
  versiya    text PRIMARY KEY,
  qollangan  timestamptz NOT NULL DEFAULT now()
);

Natija:

text
CREATE TABLE

versiya — PRIMARY KEY: bitta migratsiya ikki marta yozila olmaydi. Bu bizning birinchi himoyamiz.

Birinchi migratsiya — jadval yaratish va o'zini holat jadvaliga yozish, bitta tranzaksiyada:

sql
BEGIN;
CREATE TABLE vazifalar (
  id   bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  matn text NOT NULL
);
INSERT INTO sxema_migratsiyalari (versiya) VALUES ('001_vazifalar');
COMMIT;
SELECT versiya FROM sxema_migratsiyalari ORDER BY versiya;

Natija:

text
BEGIN
CREATE TABLE
INSERT 0 1
COMMIT
    versiya    
---------------
 001_vazifalar
(1 row)

Endi bazamiz "001-nashrda". Kimdir shu migratsiyani adashib yana ishga tushirsa-chi?

sql
BEGIN;
CREATE TABLE vazifalar (
  id   bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  matn text NOT NULL
);
INSERT INTO sxema_migratsiyalari (versiya) VALUES ('001_vazifalar');
ROLLBACK;

Natija:

text
BEGIN
ERROR:  relation "vazifalar" already exists
ERROR:  current transaction is aborted, commands ignored until end of transaction block
ROLLBACK

Birinchi xato: "vazifalar munosabati (jadvali) allaqachon mavjud". Ikkinchisi: "joriy tranzaksiya bekor qilingan, tranzaksiya bloki tugaguncha buyruqlar e'tiborsiz qoldiriladi" (Tranzaksiya asoslari dagi xatti-harakat). Haqiqiy vosita bu holatga umuman yetib bormaydi: u avval holat jadvaliga qarab, 001 ni o'tkazib yuboradi.

Tekshirib ko'ring: Nega INSERT INTO sxema_migratsiyalari migratsiyaning ichida, bir tranzaksiyada turishi kerak? Migratsiyadan keyin alohida yozsak bo'lmaydimi?

Javob

Alohida bo'lsa, ular orasida uzilish bo'lishi mumkin: jadval yaratildi, server o'chdi, holat jadvaliga yozilmadi. Keyingi safar vosita 001 ni "qo'llanmagan" deb qayta bajaradi va already exists bilan yiqiladi. Bitta tranzaksiyada esa ikkalasi ham bo'ladi yoki ikkalasi ham bo'lmaydi — holat jadvali doim haqiqatga mos.

3. Tranzaksiya: yarim qolgan migratsiya

3.1 PostgreSQL'da DDL ham tranzaksiyali

PostgreSQL'ning katta afzalligi: CREATE TABLE, ALTER TABLE ham tranzaksiya ichida ishlaydi va ROLLBACK bo'ladi (ALTER TABLE darsida ko'rgan edik). MySQL kabi ba'zi bazalarda DDL tranzaksiyani o'zi yopadi — u yerda bu himoya yo'q.

Ikkinchi migratsiya: ustun qo'shamiz, keyin yarmida xato (ataylab 1/0):

sql
BEGIN;
ALTER TABLE vazifalar
  ADD COLUMN bajarildi boolean NOT NULL DEFAULT false;
SELECT 1/0;
INSERT INTO sxema_migratsiyalari (versiya) VALUES ('002_bajarildi');
COMMIT;
SELECT count(*) AS ustun_bormi FROM information_schema.columns
WHERE table_name = 'vazifalar' AND column_name = 'bajarildi';
SELECT versiya FROM sxema_migratsiyalari ORDER BY versiya;

Natija:

text
BEGIN
ALTER TABLE
ERROR:  division by zero
ERROR:  current transaction is aborted, commands ignored until end of transaction block
ROLLBACK
 ustun_bormi 
-------------
           0
(1 row)

    versiya    
---------------
 001_vazifalar
(1 row)

Uchta narsaga qarang:

  • COMMIT o'rniga ROLLBACK chiqdi. Xatodan keyin PostgreSQL COMMIT ni ROLLBACK deb bajaradi.
  • bajarildi ustuni yo'q (0) — ALTER TABLE bajarilgan edi, lekin u ham bekor bo'ldi.
  • Holat jadvalida faqat 001. Baza toza "001-nashr" holatida qoldi. Xatoni tuzatib, migratsiyani qayta ishga tushirsangiz bo'ldi.

3.2 Hamma vosita ham shunday qilmaydi

Bu qulay xatti-harakat avtomatik emas — vosita migratsiyani tranzaksiyaga o'rashi kerak. O'lchovlar:

Vosita Yarmida xato bo'lsa Manba
Bizning SQL (BEGIN … COMMIT) Hammasi bekor Yuqorida
TypeORM 1.1.2 Sukut — hammasi bitta tranzaksiyada TypeORM
sequelize-cli 6.6.5 Birinchi qadam qoladi, yozuv yo'q Sequelize
Prisma 7.10.1 migrate deploy Birinchi qadam qoladi, "yiqilgan" yozuv Kanon tajribasi (Prisma Migrate chuqur)

Sequelize va Prisma'da yarim qolgan migratsiya qo'lda tozalashni talab qiladi. Prisma'dagi bu holat va uni tiklash — keyingi darsda.

Diqqat: Ba'zi buyruqlar tranzaksiyada umuman ishlamaydi: CREATE INDEX CONCURRENTLY, ALTER TYPE … ADD VALUE (eski versiyalarda), VACUUM. Ular uchun migratsiya tranzaksiyasiz yoziladi — va yarmida xato bo'lsa, tozalash sizning ishingiz. Bu Xavfli migratsiyalar va qulflar mavzusi.

4. Tartib va nomlash

4.1 Raqam yoki vaqt belgisi

Fayllar tartibi nomdan olinadi. Ikki usul:

  • Ketma-ket raqam: 001_, 002_, 003_ — o'qish oson. Kamchiligi: ikki dasturchi bir vaqtda 015 yozsa — to'qnashuv.
  • Vaqt belgisi: 20261025120000_toliq_ism_expand (Prisma), 1792920661943-Boshlangich (TypeORM, millisekund) — to'qnashuv deyarli yo'q. Kamchiligi: Git'da birlashtirilganda tartib yaratilish vaqti bo'yicha, birlashtirish tartibi bo'yicha emas.

Kanon ikkalasini ham ishlatadi: sql/ papkasida 001–014, 101–108 (26 va 27 qismlari to'qnashmasligi uchun 101 dan), Prisma papkasida vaqt belgisi.

4.2 Rejalashtirish — kod bilan

Vosita "qaysi migratsiyalar qo'llanmagan?" savoliga qanday javob beradi? Bu oddiy to'plam amali. Kanon holat 40 dagi migratsiyaHolati funksiyasi aynan shuni qiladi (keyinroq ko'ramiz). Soddalashtirilgan varianti — brauzerda ishlaydi:

js
function rejalashtir(koddagi, bazada) {
  const qollangan = new Set(bazada);
  const kodda = new Set(koddagi);
  return {
    kutilmoqda: [...koddagi].sort().filter((m) => !qollangan.has(m)),
    notanish: bazada.filter((m) => !kodda.has(m)),
  };
}

const koddagi = ["002_bajarildi", "001_vazifalar", "003_muddat"];
const bazada = ["001_vazifalar"];
console.log(rejalashtir(koddagi, bazada));

Konsolda:

text
{ kutilmoqda: [ '002_bajarildi', '003_muddat' ], notanish: [] }

sort() — nom bo'yicha tartiblash; shuning uchun 002 003 dan oldin, fayllar qaysi tartibda o'qilganidan qat'i nazar. Brauzer konsoli obyektni boshqacha ko'rsatishi mumkin — ma'nosi bir xil.

notanish — bazada bor, kodda yo'q migratsiya. Bu nimani bildiradi? Masalan, siz eski branch'ga qaytdingiz, baza esa yangi branch'da qo'llangan migratsiyani ko'rgan. Yoki prodakshnga yangi kod chiqdi, keyin eski versiyaga qaytarildi (rollback). Yaxshi vosita bu holatni ogohlantiradi.

js
const bazada2 = ["001_vazifalar", "002_bajarildi", "004_teglar"];
const koddagi2 = ["001_vazifalar", "002_bajarildi", "003_muddat"];
const qollangan = new Set(bazada2);
const kodda = new Set(koddagi2);
console.log(koddagi2.filter((m) => !qollangan.has(m)));
console.log(bazada2.filter((m) => !kodda.has(m)));

Konsolda:

text
[ '003_muddat' ]
[ '004_teglar' ]

Bu — ikki dasturchi parallel ishlaganda tez-tez bo'ladigan holat: 004 boshqa branch'dan bazaga tushgan, 003 esa hali qo'llanmagan. 003 ni hozir qo'llasak, u 004 dan keyin bajariladi — fayllar tartibi buzildi. Agar 003 va 004 bir jadvalga tegsa, natija kutilganidan farq qilishi mumkin.

Tekshirib ko'ring: Migratsiya tartibi nega muhim? 003_muddat (ADD COLUMN muddat) va 004_teglar (CREATE TABLE teglar) — ularning tartibi o'zgarsa, nima bo'ladi?

Javob

Bu ikkisi uchun — hech narsa: ular bir-biriga bog'liq emas. Lekin 004 muddat ustuniga indeks qursa (CREATE INDEX … (muddat)), u 003 siz yiqiladi. Vosita tartibni nomdan oladi va bog'liqlikni bilmaydi. Shuning uchun branch'larni birlashtirgandan keyin migratsiyalarni toza bazada noldan qo'llab tekshirish foydali — kanonning tekshiruv skripti ham har safar shunday qiladi.

5. up/down yoki forward-only

5.1 Ikki yondashuv

up/down — har migratsiyada ikki yo'nalish: up o'zgarishni qiladi, down uni qaytaradi. TypeORM va Sequelize'da ko'rdik: migration:revert, db:migrate:undo.

Forward-only (faqat oldinga) — migratsiya faqat up. Xato bo'lsa, uni tuzatadigan yangi migratsiya yoziladi. Prisma Migrate aynan shunday: down fayli yo'q.

up/down Forward-only
Dev'da tajriba Qulay: qo'lla, qaytar, qayta qo'lla Bazani qayta qurish kerak
Prodakshnda down ko'pincha xavfli Har tuzatish — oldinga, review bilan
down ma'lumotni qaytaradimi Yo'q (DROP COLUMN — yo'qoldi) —
Kim ishlatadi TypeORM, Sequelize, node-pg-migrate Prisma, ko'p katta jamoalar

5.2 down nega aldaydi

up: ALTER TABLE vazifalar ADD COLUMN muddat timestamptz. down: ALTER TABLE vazifalar DROP COLUMN muddat. Sxema bo'yicha mukammal juftlik. Lekin up dan keyin bir hafta o'tdi, foydalanuvchilar 500 ta muddat kiritdi. down — 500 muddat yo'qoldi.

Teskarisi yanada xavfli: up ustunni o'chiradi, down uni qaytaradi — bo'sh holda. Ma'lumot qaytmaydi.

Shuning uchun prodakshnda amaliy qoida: down — rejaning bir qismi, lekin avariya tugmasi emas. Haqiqiy qaytarish — zaxira nusxadan tiklash (Backup va restore) yoki tuzatuvchi yangi migratsiya.

6. Qo'lda ALTER va drift

6.1 Qo'lda ALTER xavfi

Prodakshnda sekin so'rov bor. Malika serverga ulanib, qo'lda indeks qo'shdi: CREATE INDEX vazifalar_muddat_idx …. Muammo hal bo'ldi. Bir oydan keyin:

  • Yangi test serveri migratsiyalardan qurildi — unda indeks yo'q. Test tez ishlamaydi, sababi topilmaydi.
  • Kimdir xuddi shu indeksni migratsiyaga qo'shdi — prodakshnda relation "vazifalar_muddat_idx" already exists, deploy yiqildi.
  • ORM vositasi (prisma migrate dev, typeorm migration:generate) "bazada noma'lum indeks bor" deb uni o'chirishni taklif qiladi.

Bu — drift: bazaning haqiqiy sxemasi migratsiyalar tarixidan farq qiladi. Qoida oddiy: har sxema o'zgarishi — migratsiya fayli orqali. Shoshilinch holatda qo'lda qilingan bo'lsa — darhol uni ifodalaydigan migratsiya yoziladi (CREATE INDEX IF NOT EXISTS bilan, prodakshnda ham xatosiz o'tadi).

6.2 Qo'llangan fayl o'zgarmaydi

Eng muhim qoida — 26-qismdan beri takrorlanadi: qo'llangan migratsiya fayli tahrirlanmaydi. Nega? 001 ni tahrirladingiz. Sizning yangi bazangizda yangi variant qo'llanadi. Prodakshnda esa 001 allaqachon "qo'llangan" — vosita uni qayta bajarmaydi. Endi ikki baza bir xil fayl nomi bilan har xil sxemaga ega.

Ba'zi vositalar buni tutadi: Prisma har fayl uchun checksum saqlaydi. Lekin kanon tajribasi muhim nuqtani ko'rsatdi: fayl o'zgartirilganda prisma migrate status baribir "Database schema is up to date!" dedi — checksum'ni faqat migrate dev tekshiradi. Ya'ni vositaga to'liq ishonmang, qoidaga amal qiling.

Kanondagi bitta istisno ochiq aytilgan: 106 fayli (ALTER DEFAULT PRIVILEGES FOR ROLE postgres) boshqa nomli superuser'li bazada yiqildi va CURRENT_USER ga tuzatildi. Kurs loyihasi hali hech qaysi "prodakshn"ga chiqmagani uchun fayl joyida tuzatildi — bu ongli istisno. Haqiqiy loyihada buning o'rniga yangi 109 migratsiyasi yozilardi: qo'llangan 106 o'zgarmaydi, 109 default huquqlarni to'g'ri rol uchun qayta beradi.

Tekshirib ko'ring: Siz 005_teglar.sql ni yozib, o'z bazangizga qo'lladingiz, lekin hali git push qilmadingiz. Unda xato topdingiz. Faylni tahrirlash mumkinmi?

Javob

Ha — fayl faqat sizning bazangizda qo'llangan va hech kimga tarqalmagan. Tahrirlang, o'z bazangizda qaytaring (down yoki bazani qayta qurish) va qayta qo'llang. Qoida "boshqa muhitga chiqqan fayl o'zgarmaydi" — birinchi push (va ayniqsa birinchi deploy) dan keyin fayl muzlaydi.

7. Ko'p uchraydigan xatolar

1. relation "…" already exists deploy'da. Kimdir obyektni qo'lda yaratgan yoki holat jadvaliga yozilmay qolgan. Tuzatish: drift sababini topish; obyekt to'g'ri bo'lsa — migratsiyani "qo'llangan" deb belgilash (Prisma migrate resolve --applied, TypeORM --fake).

2. Yarim qolgan migratsiya. Tranzaksiyasiz vositada (sequelize-cli, Prisma) birinchi qadam qoldi. Tuzatish: qolgan qismni qo'lda qaytarish, keyin qayta ishga tushirish; kelajakda — migratsiyani kichik va tranzaksiyali qilish.

3. Branch'lar birlashganda tartib. Yuqoridagi 003/004 holati. Tuzatish: birlashtirgandan keyin toza bazada hamma migratsiyani noldan qo'llab tekshirish.

4. Bitta migratsiyada sxema va katta ma'lumot o'zgarishi. 1 mln qatorni UPDATE qiladigan migratsiya jadvalni uzoq qulflaydi. Tuzatish: sxema — migratsiyada, katta ma'lumot ko'chirish — partiyalab, alohida (Zero-downtime: expand-contract).

5. Seed ma'lumot migratsiyada. Test foydalanuvchilarini migratsiyaga yozish — ular prodakshnga ham tushadi. Tuzatish: ma'lumotnoma (o'zgarmas) jadvallar — migratsiyada mumkin; demo ma'lumot — seed'da (Seeding va test ma'lumotlari).

8. Mashqlar

Yechimlar tekshirilgan (biz ishga tushirdik, PostgreSQL 17.6, Node 24.21.0).

1-mashq (oson)

sxema_migratsiyalari jadvalida 001_vazifalar, 002_bajarildi bor. Koddagi fayllar: 001_vazifalar, 002_bajarildi, 003_muddat, 004_teglar. Vosita keyingi ishga tushishda qaysi fayllarni qaysi tartibda bajaradi? Agar 003 yiqilsa-chi?

Yechim

003_muddat, keyin 004_teglar. Agar 003 yiqilsa (tranzaksiyali vositada) — 003 bekor bo'ladi, holat jadvalida 001, 002 qoladi va vosita to'xtaydi: 004 bajarilmaydi. Tartib buzilmasligi uchun xatodan keyin davom etilmaydi.

2-mashq (o'rta)

rejalashtir funksiyasini kengaytiring: natijaga xato maydoni qo'shing. Agar kutilayotgan biror migratsiya nomi bazadagi eng oxirgi qo'llangan nomdan kichik bo'lsa (tartib buzilgan), xato: "tartib buzilgan: <nom>", aks holda xato: null. Sinang: koddagi = ["001_a", "002_b", "003_c", "004_d"], bazada = ["001_a", "002_b", "004_d"]. Ishora: satrlarni < bilan solishtirish — lug'at tartibida (Taqqoslash operatorlari); eng kattasi — bazada.toSorted().at(-1) (toSorted).

Yechim
js
function rejalashtir(koddagi, bazada) {
  const qollangan = new Set(bazada);
  const kutilmoqda = koddagi.toSorted()
    .filter((m) => !qollangan.has(m));
  const oxirgi = bazada.toSorted().at(-1) ?? "";
  const buzilgan = kutilmoqda.find((m) => m < oxirgi);
  return {
    kutilmoqda,
    xato: buzilgan ? `tartib buzilgan: ${buzilgan}` : null,
  };
}
console.log(rejalashtir(["001_a", "002_b", "003_c", "004_d"],
  ["001_a", "002_b", "004_d"]));
console.log(rejalashtir(["001_a", "002_b", "003_c"],
  ["001_a"]));

Konsolda:

text
{ kutilmoqda: [ '003_c' ], xato: 'tartib buzilgan: 003_c' }
{ kutilmoqda: [ '002_b', '003_c' ], xato: null }

003_c — 004_d dan kichik, lekin hali qo'llanmagan: u boshqa branch'dan kech kelgan. Ba'zi vositalar bu holatda to'xtaydi (node-pg-migrate — sukut bo'yicha; --no-check-order bilan o'tkazib yuboradi, buni ORM'siz migratsiya vositalari darsida ko'rasiz).

3-mashq (qiyin)

Qo'lda mexanizmimizga 003_muddat migratsiyasini yozing: vazifalar ga muddat timestamptz ustuni va unga indeks. Migratsiya ikki marta ishga tushirilsa ham xato bermasin (ikkinchi safar hech narsa qilmasin) va holat jadvaliga bir marta yozilsin. Ishora: IF NOT EXISTS (ADD COLUMN IF NOT EXISTS, CREATE INDEX IF NOT EXISTS) va ON CONFLICT DO NOTHING (UPSERT va MERGE).

Yechim
sql
CREATE TABLE sxema_migratsiyalari (versiya text PRIMARY KEY,
  qollangan timestamptz NOT NULL DEFAULT now());
CREATE TABLE vazifalar (id bigint GENERATED ALWAYS AS IDENTITY
  PRIMARY KEY, matn text NOT NULL);
-- 003_muddat — ikki marta
BEGIN;
ALTER TABLE vazifalar ADD COLUMN IF NOT EXISTS muddat timestamptz;
CREATE INDEX IF NOT EXISTS vazifalar_muddat_idx
  ON vazifalar (muddat);
INSERT INTO sxema_migratsiyalari (versiya) VALUES ('003_muddat')
  ON CONFLICT (versiya) DO NOTHING;
COMMIT;
BEGIN;
ALTER TABLE vazifalar ADD COLUMN IF NOT EXISTS muddat timestamptz;
CREATE INDEX IF NOT EXISTS vazifalar_muddat_idx
  ON vazifalar (muddat);
INSERT INTO sxema_migratsiyalari (versiya) VALUES ('003_muddat')
  ON CONFLICT (versiya) DO NOTHING;
COMMIT;
SELECT versiya FROM sxema_migratsiyalari;
text
NOTICE:  column "muddat" of relation "vazifalar" already exists, skipping
NOTICE:  relation "vazifalar_muddat_idx" already exists, skipping
  versiya   
------------
 003_muddat
(1 row)

Natija (psql -q — buyruq teglarisiz). Ikkinchi marta PostgreSQL xato emas, NOTICE ("allaqachon bor, o'tkazildi") berdi; ON CONFLICT DO NOTHING holat jadvaliga dublikat yozmadi. Bunday "qayta ishga tushirishga chidamli" migratsiya ayniqsa tranzaksiyasiz vositalarda (sequelize-cli, Prisma) foydali: yarmida yiqilsa, qayta urinish already exists bilan to'xtamaydi.

Lekin chegarasini biling: IF NOT EXISTS faqat nomni tekshiradi. Bazada xuddi shu nomli, lekin boshqa ustunga qurilgan indeks bo'lsa — u ham "bor" deb o'tkaziladi.

9. Loyiha qadami

9.1 Kanonimizning sxemasi allaqachon migratsiyalar

vazifalar loyihasining sql/ papkasiga qarang — u migratsiya fayllari to'plami: raqamli nom, tartib, har fayl bitta o'zgarish, qo'llangan fayl o'zgarmaydi. Kanon qur.sh skripti har faylni psql -1 (bitta tranzaksiya) bilan qo'llaydi va birinchi xatoda to'xtaydi — «Tranzaksiya: yarim qolgan migratsiya» bo'limidagi himoya.

Faqat bitta qism yetishmaydi: holat jadvali. qur.sh har safar bazani noldan quradi, shuning uchun "qaysi fayl qo'llangan?" degan savolga ehtiyoj yo'q edi. Mavjud, ma'lumotli bazaga yangi fayl qo'llash uchun esa u shart.

9.2 Holat 36 ga tayyorgarlik

Keyingi darsda (holat 36) kanon buni Prisma Migrate bilan hal qiladi: sql/ dagi namunasiz fayllar (001–014, 101, 103–106) birlashtirilib, prisma/migrations/0_init/migration.sql — baseline (boshlang'ich nuqta) bo'ladi. Holat jadvali — _prisma_migrations.

Hozir o'z repongizda faqat tekshiring: sql/ fayllar noldan xatosiz qo'llanadimi (26-qismdagi qur.sh yoki o'zingizning npm run sxema skriptingiz) va git status toza bo'lsin. Bu darsda commit yo'q — holat 36 ning commit'i keyingi darsda, Prisma Migrate bilan birga.

10. Real ishda

  • Har backend jamoada migratsiya vositasi bor; birinchi ish kunida "migratsiyalar qayerda va qanday qo'llanadi?" deb so'rang.
  • Kod review'da migratsiya fayllari alohida diqqat bilan o'qiladi: ular prodakshn bazasiga teginadi va qaytarilishi qiyin.
  • CI odatda bo'sh bazada hamma migratsiyani noldan qo'llaydi — tartib va sintaksis xatolari shu yerda ushlanadi (Migratsiyani deploy jarayonida qo'llash).
  • Intervyuda: "Migratsiya nima va nega kerak?", "down migratsiyaga ishonasizmi?", "Prodakshnda qo'lda ALTER qildingiz — keyin nima qilasiz?".

Xulosa

  • Migratsiya — raqamli, Git'dagi sxema o'zgarishi fayli; vosita holat jadvaliga qarab qo'llanmaganlarini tartib bilan bajaradi.
  • Migratsiya va holat jadvaliga yozuv — bitta tranzaksiyada; PostgreSQL DDL'ni ham ROLLBACK qiladi, biz buni 1/0 bilan ko'rdik.
  • Sequelize va Prisma migratsiyani tranzaksiyaga o'ramaydi — yarim qolgan holat qo'lda tozalanadi.
  • down sxemani qaytaradi, ma'lumotni emas; prodakshnda forward-only va zaxira nusxa ishonchliroq.
  • Qo'lda ALTER — drift; qo'llangan fayl tahrirlanmaydi, xato yangi migratsiya bilan tuzatiladi.

Keyingi dars: Prisma Migrate chuqur — migrate dev va deploy, shadow baza, baseline, migrate diff, resolve va drift'ni haqiqiy kanon chiqishlarida.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Migratsiya: sxema o'zgarishlarini kod kabi versiyalash — IlmHamroh