Database migration - database strukturasini tartibli, versiyalangan va nazoratli o‘zgartirish usuli.
Bu bo‘lim ichida quyidagilar bor: Flyway setup, V1__init.sql convention, Liquibase alternative, migration versioning strategy, spring.jpa.hibernate.ddl-auto va nima uchun production’da ehtiyot bo‘lish kerakligi.
1. Database migration nima?
Backend projectda database doim o‘zgaradi:
users jadvali qo‘shiladi
products jadvali qo‘shiladi
email column unique bo‘ladi
price column qo‘shiladi
index qo‘shiladi
foreign key qo‘shiladiAgar bularni qo‘lda database ichida o‘zgartirsak, muammo chiqadi:
Developer A database’da column qo‘shdi
Developer B bilmay qoldi
Production database boshqacha
Local database boshqacha
Test database boshqachaShu muammoni migration tool hal qiladi.
Migration - database o‘zgarishlarini faylga yozib, Git orqali saqlash.
Masalan:
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(19, 2) NOT NULL
);Bu SQL fayl project ichida turadi.
2. Migration nima uchun kerak?
Migration ishlatilsa:
Database tarixi saqlanadi
Har bir o‘zgarish versiya bilan yuradi
Local, test, production database bir xil bo‘ladi
Team bilan ishlash osonlashadi
Deployment avtomatlashtiriladi
Rollback/recovery tushunarli bo‘ladiOddiy qilib:
Code Git’da yuradi.
Database structure ham Git’da yurishi kerak.3. Migration bo‘lmasa nima bo‘ladi?
Tasavvur qiling, siz Product entity qo‘shdingiz:
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal price;
}Local’da ishladi. Chunki siz ddl-auto=update qilib qo‘ygansiz.
Lekin serverda error chiqdi:
relation "products" does not existNega?
Chunki production database’da products table yo‘q.
Migration bo‘lsa, bu table yaratish SQL fayl sifatida projectga qo‘shilgan bo‘lardi.
4. spring.jpa.hibernate.ddl-auto nima?
Spring Boot’da Hibernate database tablelarni avtomatik yaratishi yoki o‘zgartirishi mumkin.
spring:
jpa:
hibernate:
ddl-auto: updateEng ko‘p uchraydigan qiymatlar:
Qiymat | Ma’nosi |
|---|---|
| Hibernate schema’ga tegmaydi |
| Entity va database mosligini tekshiradi |
| Entityga qarab database’ni update qilishga urinadi |
| Har startda schema yaratadi |
| Startda yaratadi, stopda o‘chiradi |
5. Nega ddl-auto=update production’da yomon?
ddl-auto=update qulay ko‘rinadi, lekin production’da xavfli.
Sabablari:
Database o‘zgarishlari Git’da ko‘rinmaydi
Hibernate nima SQL ishlatishini to‘liq nazorat qilmaysiz
Column rename noto‘g‘ri tushunilishi mumkin
Data yo‘qolish xavfi bor
Index, constraint, default value kabi narsalar aniq boshqarilmaydi
Teamda kim nima o‘zgartirgani bilinmaydiMasalan siz field nomini o‘zgartirdingiz:
private String fullName;keyin:
private String name;Hibernate buni rename deb tushunmasligi mumkin. U yangi name column yaratib qo‘yishi mumkin. Eski full_name column qolib ketadi.
Production uchun yaxshiroq:
spring:
jpa:
hibernate:
ddl-auto: validateyoki:
spring:
jpa:
hibernate:
ddl-auto: noneDatabase o‘zgarishlarini esa Flyway yoki Liquibase boshqaradi.
6. Flyway nima?
Flyway - database migration tool.
U project ichidagi SQL migration fayllarni o‘qiydi va database’ga navbat bilan qo‘llaydi.
Spring Boot bilan juda oson ishlaydi.
Flow:
Application start bo‘ladi
↓
Flyway migration fayllarni tekshiradi
↓
Qaysi migrationlar hali ishlamaganini aniqlaydi
↓
Ularni database’da bajaradi
↓
Application normal ishga tushadi7. Flyway dependency
Maven
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>PostgreSQL ishlatsangiz, ko‘pincha buni ham qo‘shiladi:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>Gradle
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-database-postgresql'8. Flyway migration fayllari qayerda turadi?
Default joy:
src/main/resources/db/migrationMasalan:
src/main/resources/db/migration
├── V1__init.sql
├── V2__create_products_table.sql
├── V3__add_category_to_products.sql
└── V4__create_users_table.sqlFlyway application start bo‘lganda shu papkani o‘qiydi.
9. Flyway fayl nomlash qoidasi
Flyway fayllar odatda shunday nomlanadi:
V1__init.sqlFormat:
V<version>__<description>.sqlMuhim: V1 dan keyin ikkita underscore bo‘ladi:
V1__init.sqlNoto‘g‘ri:
V1_init.sqlTo‘g‘ri:
V1__init.sqlMisollar:
V1__init.sql
V2__create_products.sql
V3__add_price_to_products.sql
V4__create_orders.sql10. Birinchi migration: V1__init.sql
Masalan product/category project uchun:
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(19, 2) NOT NULL,
quantity INTEGER NOT NULL DEFAULT 0,
category_id BIGINT NOT NULL,
CONSTRAINT fk_products_category
FOREIGN KEY (category_id)
REFERENCES categories(id)
);Bu fayl:
src/main/resources/db/migration/V1__init.sqlichida bo‘ladi.
Application ishga tushganda Flyway shu SQL’ni database’da bajaradi.
11. Flyway database’da nimani saqlaydi?
Flyway database ichida maxsus table yaratadi:
flyway_schema_historyBu table ichida qaysi migrationlar bajarilgani saqlanadi.
Taxminan:
installed_rank | version | description | script | success |
|---|---|---|---|---|
1 | 1 | init | V1__init.sql | true |
2 | 2 | create products | V2__create_products.sql | true |
Shuning uchun Flyway bir migrationni qayta-qayta ishlatmaydi.
Agar V1__init.sql allaqachon bajarilgan bo‘lsa, keyingi startda uni skip qiladi.
12. Yangi o‘zgarish qo‘shish
Masalan products table’ga description column qo‘shish kerak.
Yomon yo‘l:
ALTER TABLE products ADD COLUMN description TEXT;Buni database’da qo‘lda bajarib qo‘yish.
To‘g‘ri yo‘l:
Yangi migration fayl yaratiladi:
V2__add_description_to_products.sqlIchida:
ALTER TABLE products
ADD COLUMN description TEXT;Endi Git’da ham ko‘rinadi:
V1__init.sql
V2__add_description_to_products.sqlTeamdagi boshqa developer projectni pull qilsa, application start bo‘lganda Flyway uning local database’iga ham description column qo‘shadi.
13. Migration faylni o‘zgartirish mumkinmi?
Muhim qoida:
Bajarilgan migration faylni o‘zgartirmang.Masalan V1__init.sql production’da ishlagan bo‘lsa, keyin uni edit qilish yomon.
Nega?
Flyway migration fayllarning checksum’ini saqlaydi. Agar ishlagan migration faylni o‘zgartirsangiz, Flyway error beradi.
Sababi: database tarixi buzilmasligi kerak.
To‘g‘ri yo‘l:
Eski migrationni o‘zgartirmang.
Yangi migration yarating.Masalan:
V3__alter_products_name_length.sqlALTER TABLE products
ALTER COLUMN name TYPE VARCHAR(150);14. Migration versioning strategy
Kichik projectlarda oddiy ketma-ket raqam yetadi:
V1__init.sql
V2__create_products.sql
V3__add_description.sqlLekin team katta bo‘lsa, conflict chiqishi mumkin.
Masalan ikki developer bir vaqtda yaratdi:
Developer A: V5__add_orders.sql
Developer B: V5__add_payments.sqlConflict.
Bunday holatda timestamp ishlatish mumkin:
V202605211030__create_orders.sql
V202605211045__create_payments.sqlFormat:
VYYYYMMDDHHMM__description.sqlMasalan:
V202605211030__create_users_table.sql
V202605211045__add_index_to_users_email.sqlBu conflict ehtimolini kamaytiradi.
15. Flyway config
application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/shop_db
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: validate
show-sql: true
flyway:
enabled: true
locations: classpath:db/migrationBu yerda:
ddl-auto: validateHibernate schema yaratmaydi, faqat entity va database mosligini tekshiradi.
flyway.enabled: trueFlyway migrationlarni ishlatadi.
16. Local development uchun nima qilish kerak?
Local’da boshlanish uchun ba’zida:
spring:
jpa:
hibernate:
ddl-auto: updateishlatiladi.
Lekin boshlang'ich bosqichidayoq yaxshi odat:
spring:
jpa:
hibernate:
ddl-auto: validateva Flyway migration yozish.
Development uchun:
Entity yozdingiz
Migration SQL yozdingiz
Application start qildingiz
Flyway migrationni bajardi
Hibernate validate qildiBu professional workflow.
17. Entity va migration mos bo‘lishi kerak
Agar entity:
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(nullable = false)
private BigDecimal price;
}bo‘lsa, migration ham mos bo‘lishi kerak:
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(19, 2) NOT NULL
);Agar entity’da name bor, lekin database’da product_name bo‘lsa, ddl-auto=validate error beradi.
Bu yaxshi. Chunki xatoni application startida bilib olasiz.
18. Index qo‘shish
Database performance uchun index kerak bo‘ladi.
Masalan email bo‘yicha ko‘p qidiramiz:
Optional<AppUser> findByUsername(String username);Migration:
CREATE UNIQUE INDEX ux_users_username
ON users(username);Yoki table ichida:
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT true
);Agar keyin qo‘shilsa:
V3__add_unique_index_to_users_username.sqlCREATE UNIQUE INDEX ux_users_username
ON users(username);19. Foreign key qo‘shish
Masalan products.category_id categories.idga bog‘langan.
ALTER TABLE products
ADD CONSTRAINT fk_products_category
FOREIGN KEY (category_id)
REFERENCES categories(id);Bu database darajasida himoya qiladi.
Ya’ni product mavjud bo‘lmagan category’ga bog‘lanib qolmaydi.
20. Default value qo‘shish
Masalan enabled default true bo‘lsin:
ALTER TABLE users
ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT true;Agar table ichida yaratilsa:
enabled BOOLEAN NOT NULL DEFAULT trueBu foydali, chunki eski data uchun ham qiymat bo‘ladi.
21. NOT NULL column qo‘shishda ehtiyot bo‘lish
Agar table’da oldindan data bo‘lsa, bunday migration xato berishi mumkin:
ALTER TABLE products
ADD COLUMN status VARCHAR(30) NOT NULL;Nega?
Chunki eski rows uchun status qiymati yo‘q.
Yaxshiroq:
ALTER TABLE products
ADD COLUMN status VARCHAR(30) NOT NULL DEFAULT 'ACTIVE';Yoki ikki bosqichda:
ALTER TABLE products
ADD COLUMN status VARCHAR(30);
UPDATE products
SET status = 'ACTIVE'
WHERE status IS NULL;
ALTER TABLE products
ALTER COLUMN status SET NOT NULL;Bu production’da xavfsizroq.
22. Data migration
Migration faqat table yaratish emas. Data o‘zgartirish ham bo‘lishi mumkin.
Masalan eski productlarda quantity null bo‘lsa:
UPDATE products
SET quantity = 0
WHERE quantity IS NULL;Keyin constraint:
ALTER TABLE products
ALTER COLUMN quantity SET NOT NULL;23. Seed data qo‘shish
Local yoki test uchun boshlang‘ich data kerak bo‘lishi mumkin.
Masalan:
V2__insert_initial_categories.sqlINSERT INTO categories (name)
VALUES
('Electronics'),
('Food'),
('Clothes');Lekin production seed data’da ehtiyot bo‘ling. Har bir insert idempotent bo‘lgani yaxshi.
PostgreSQL’da:
INSERT INTO categories (name)
VALUES ('Electronics')
ON CONFLICT (name) DO NOTHING;24. Repeatable migration
Flyway’da oddiy versioned migrationlardan tashqari repeatable migration ham bor.
Nomlash:
R__create_views.sqlR__ bilan boshlanadi.
U checksum o‘zgarsa qayta ishlaydi.
Ko‘proq view, function, procedure kabi obyektlar uchun ishlatiladi.
Boshlang'ich bosqichida avval V1, V2, V3 migrationlarni yaxshi tushunish yetarli.
25. Liquibase nima?
Liquibase - Flywayga alternativ migration tool.
Flyway ko‘pincha SQL fayllar bilan sodda ishlaydi.
Liquibase esa migrationlarni bir nechta formatda yozishga imkon beradi:
XML
YAML
JSON
SQLMasalan Liquibase YAML:
databaseChangeLog:
- changeSet:
id: 1
author: jahon
changes:
- createTable:
tableName: categories
columns:
- column:
name: id
type: BIGSERIAL
constraints:
primaryKey: true
- column:
name: name
type: VARCHAR(100)
constraints:
nullable: false
unique: trueFlyway vs Liquibase
Tool | Qachon qulay |
|---|---|
Flyway | Oddiy, SQL-first, tushunish oson |
Liquibase | Katta enterprise, ko‘p DB support, rollback metadata kerak bo‘lsa |
Java developer uchun tavsiya:
Avval Flyway o‘rganing.
Keyin Liquibase nima ekanini bilib qo‘ying.26. Product API uchun migrationlar
Oldingi loyihamizga mos migrationlar.
V1__create_categories_table.sql
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE
);V2__create_products_table.sql
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(19, 2) NOT NULL,
quantity INTEGER NOT NULL DEFAULT 0,
category_id BIGINT NOT NULL,
CONSTRAINT fk_products_category
FOREIGN KEY (category_id)
REFERENCES categories(id)
);V3__insert_initial_categories.sql
INSERT INTO categories (name)
VALUES
('Electronics'),
('Food'),
('Clothes');V4__add_description_to_products.sql
ALTER TABLE products
ADD COLUMN description TEXT;27. Security darsidan keyingi users migration
Oldingi Spring Security mavzusida AppUser entity bor edi.
Migration:
V5__create_users_table.sqlCREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT true
);
CREATE UNIQUE INDEX ux_users_username
ON users(username);Entity:
@Entity
@Table(name = "users")
public class AppUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 100)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false, length = 50)
private String role;
@Column(nullable = false)
private boolean enabled = true;
}28. Migration bilan @Entity annotationlar munosabati
Entity’dagi annotationlar:
@Column(nullable = false, length = 100)database’ni yaratib bermasligi kerak, agar Flyway ishlatayotgan bo‘lsangiz.
Ular ko‘proq:
Hibernate validate qilishiga yordam beradi
Kod o‘qilganda constraintni ko‘rsatadi
JPA mappingni aniqlaydiLekin haqiqiy schema:
CREATE TABLE ...
ALTER TABLE ...migration fayllarda bo‘ladi.
29. Flyway error: migration o‘zgargan bo‘lsa
Agar oldin bajarilgan migrationni edit qilsangiz, Flyway checksum error berishi mumkin.
Masalan:
Validate failed: Migration checksum mismatchBunday holatda production’da migrationni o‘zgartirmang. Yangi migration yarating.
Local developmentda, agar database muhim bo‘lmasa, local DB’ni tozalab qaytadan migration qilish mumkin.
Masalan Docker database bo‘lsa:
docker compose down -v
docker compose up -dLekin production’da bunday qilinmaydi.
30. Migration yozishda eng yaxshi amaliyotlar
1. Har bir o‘zgarish alohida fayl
Yomon:
V2__many_changes.sqlIchida hamma narsa aralash.
Yaxshiroq:
V2__create_products_table.sql
V3__add_product_description.sql
V4__add_product_indexes.sql2. Bajarilgan migrationni edit qilmang
Eski migration tarix.
Yangi o‘zgarish yangi migration.3. Production’da ddl-auto=update ishlatmang
Yaxshi variant:
spring:
jpa:
hibernate:
ddl-auto: validate4. Constraintlarni database’da ham yozing
Faqat DTO validation yetarli emas.
name VARCHAR(100) NOT NULL
username VARCHAR(100) NOT NULL UNIQUE
price NUMERIC(19,2) NOT NULL5. Indexlarni unutmang
Ko‘p qidiriladigan columnlarga index:
CREATE INDEX ix_products_category_id
ON products(category_id);6. Migrationni local’da tekshirib keyin push qiling
Application start bo‘ldimi?
Flyway migration successmi?
Hibernate validate successmi?
Repository querylar ishlayaptimi?31. Ko‘p uchraydigan xatolar
Xato 1: ddl-auto=updatega suyanish
Yomon:
spring:
jpa:
hibernate:
ddl-auto: updateProduction uchun xavfli.
Yaxshiroq:
spring:
jpa:
hibernate:
ddl-auto: validateXato 2: Migration fayl nomida bitta underscore
Yomon:
V1_init.sqlTo‘g‘ri:
V1__init.sqlXato 3: Bajarilgan migrationni edit qilish
Yomon:
V1__init.sql faylni production’dan keyin o‘zgartirishTo‘g‘ri:
V2__add_column.sql yaratishXato 4: NOT NULL columnni default value’siz qo‘shish
Yomon:
ALTER TABLE products
ADD COLUMN status VARCHAR(30) NOT NULL;Yaxshiroq:
ALTER TABLE products
ADD COLUMN status VARCHAR(30) NOT NULL DEFAULT 'ACTIVE';Xato 5: Foreign key yozmaslik
Yomon:
category_id BIGINT NOT NULLYaxshiroq:
category_id BIGINT NOT NULL,
CONSTRAINT fk_products_category
FOREIGN KEY (category_id)
REFERENCES categories(id)32. Java developer uchun qisqa qoida
Entity - Java modeli
Migration - database haqiqati
Flyway - migrationlarni tartib bilan ishlatadi
ddl-auto=validate - entity va database mosligini tekshiradi
ddl-auto=update - production’da xavfli
Bajarilgan migration - o‘zgartirilmaydi
Yangi o‘zgarish - yangi migration fayl33. Amaliy vazifa
Oldingi Product CRUD API loyihasiga Flyway qo‘shing.
1. Dependency qo‘shing
flyway-core
flyway-database-postgresql2. Papka yarating
src/main/resources/db/migration3. Migration fayllar
V1__create_categories_table.sql
V2__create_products_table.sql
V3__create_users_table.sql
V4__insert_initial_categories.sql4. application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/shop_db
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: validate
show-sql: true
flyway:
enabled: true
locations: classpath:db/migration5. Tekshirish
Application start bo‘lganda database’da quyidagilar bo‘lsin:
categories
products
users
flyway_schema_historyXulosa
Database migrations - real backend projectlarda majburiy ko‘nikma.
Java developer quyidagilarni bilishi kerak:
Flyway nima?
Migration fayllar qayerda turadi?
V1__init.sql nomlash qoidasi
flyway_schema_history nima?
Nega bajarilgan migration edit qilinmaydi?
ddl-auto=update production’da nega xavfli?
ddl-auto=validate nima qiladi?
Foreign key, unique, index, default value qanday yoziladi?
Liquibase Flywayga qanday alternativa?Eng muhim professional qoida:
Database o‘zgarishi qo‘lda emas, migration orqali qilinadi.