Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Migratsiya nima
- 2.1 Uchta tarkibiy qism
- 2.2 Qo'lda yasab ko'ramiz
- 3. Tranzaksiya: yarim qolgan migratsiya
- 3.1 PostgreSQL'da DDL ham tranzaksiyali
- 3.2 Hamma vosita ham shunday qilmaydi
- 4. Tartib va nomlash
- 4.1 Raqam yoki vaqt belgisi
- 4.2 Rejalashtirish — kod bilan
- 5. up/down yoki forward-only
- 5.1 Ikki yondashuv
- 5.2 down nega aldaydi
- 6. Qo'lda ALTER va drift
- 6.1 Qo'lda ALTER xavfi
- 6.2 Qo'llangan fayl o'zgarmaydi
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson)
- 2-mashq (o'rta)
- 3-mashq (qiyin)
- 9. Loyiha qadami
- 9.1 Kanonimizning sxemasi allaqachon migratsiyalar
- 9.2 Holat 36 ga tayyorgarlik
- 10. Real ishda
- Xulosa
- Manbalar
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/downva forward-only yondashuvlarini solishtirasiz.- Qo'lda
ALTERning 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
107ni qo'ldapsqlbilan qo'llash — mumkin. Lekin: hamkasbingizning noutbukida107qo'llanganmi? Test serverida-chi? Kecha Sardor105ni 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):
CREATE TABLE sxema_migratsiyalari (
versiya text PRIMARY KEY,
qollangan timestamptz NOT NULL DEFAULT now()
);Natija:
CREATE TABLEversiya — PRIMARY KEY: bitta migratsiya ikki marta yozila olmaydi. Bu bizning birinchi himoyamiz.
Birinchi migratsiya — jadval yaratish va o'zini holat jadvaliga yozish, bitta tranzaksiyada:
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:
BEGIN
CREATE TABLE
INSERT 0 1
COMMIT
versiya
---------------
001_vazifalar
(1 row)Endi bazamiz "001-nashrda". Kimdir shu migratsiyani adashib yana ishga tushirsa-chi?
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:
BEGIN
ERROR: relation "vazifalar" already exists
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACKBirinchi 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_migratsiyalarimigratsiyaning 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):
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:
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:
COMMITo'rnigaROLLBACKchiqdi. Xatodan keyin PostgreSQLCOMMITniROLLBACKdeb bajaradi.bajarildiustuni yo'q (0) —ALTER TABLEbajarilgan 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 vaqtda015yozsa — 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:
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:
{ 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.
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:
[ '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) va004_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.sqlni yozib, o'z bazangizga qo'lladingiz, lekin haligit pushqilmadingiz. 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
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:
{ 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
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;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?", "
downmigratsiyaga ishonasizmi?", "Prodakshnda qo'ldaALTERqildingiz — 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
ROLLBACKqiladi, biz buni1/0bilan ko'rdik. - Sequelize va Prisma migratsiyani tranzaksiyaga o'ramaydi — yarim qolgan holat qo'lda tozalanadi.
downsxemani 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
- PostgreSQL 18 hujjati — Transactions,
CREATE INDEX(CONCURRENTLYtranzaksiya cheklovi): https://www.postgresql.org/docs/18/sql-createindex.html - Prisma hujjati — Prisma Migrate, mental model: https://www.prisma.io/docs/orm/prisma-migrate
- IlmHamroh kanon:
qur.sh, t36-migrate (checksum), t38-expand-contract (Prisma tranzaksiyasizligi),106tuzatishi (2026-10-25); darsdagi SQL — biz ishga tushirdik (PostgreSQL 17.6, Windows 11), 2026-10-27.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!