Database Migrations

01.07.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Spring Boot | 22 daqiqa o'qish

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‘shiladi

Agar 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 boshqacha

Shu 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‘ladi

Oddiy 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 exist

Nega?

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: update

Eng ko‘p uchraydigan qiymatlar:

Qiymat

Ma’nosi

none

Hibernate schema’ga tegmaydi

validate

Entity va database mosligini tekshiradi

update

Entityga qarab database’ni update qilishga urinadi

create

Har startda schema yaratadi

create-drop

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 bilinmaydi

Masalan 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: validate

yoki:

spring:
  jpa:
    hibernate:
      ddl-auto: none

Database 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 tushadi

7. 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/migration

Masalan:

src/main/resources/db/migration
 ├── V1__init.sql
 ├── V2__create_products_table.sql
 ├── V3__add_category_to_products.sql
 └── V4__create_users_table.sql

Flyway application start bo‘lganda shu papkani o‘qiydi.


9. Flyway fayl nomlash qoidasi

Flyway fayllar odatda shunday nomlanadi:

V1__init.sql

Format:

V<version>__<description>.sql

Muhim: V1 dan keyin ikkita underscore bo‘ladi:

V1__init.sql

Noto‘g‘ri:

V1_init.sql

To‘g‘ri:

V1__init.sql

Misollar:

V1__init.sql
V2__create_products.sql
V3__add_price_to_products.sql
V4__create_orders.sql

10. 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.sql

ichida 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_history

Bu 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.sql

Ichida:

ALTER TABLE products
ADD COLUMN description TEXT;

Endi Git’da ham ko‘rinadi:

V1__init.sql
V2__add_description_to_products.sql

Teamdagi 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.sql
ALTER 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.sql

Lekin team katta bo‘lsa, conflict chiqishi mumkin.

Masalan ikki developer bir vaqtda yaratdi:

Developer A: V5__add_orders.sql
Developer B: V5__add_payments.sql

Conflict.

Bunday holatda timestamp ishlatish mumkin:

V202605211030__create_orders.sql
V202605211045__create_payments.sql

Format:

VYYYYMMDDHHMM__description.sql

Masalan:

V202605211030__create_users_table.sql
V202605211045__add_index_to_users_email.sql

Bu 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/migration

Bu yerda:

ddl-auto: validate

Hibernate schema yaratmaydi, faqat entity va database mosligini tekshiradi.

flyway.enabled: true

Flyway migrationlarni ishlatadi.


16. Local development uchun nima qilish kerak?

Local’da boshlanish uchun ba’zida:

spring:
  jpa:
    hibernate:
      ddl-auto: update

ishlatiladi.

Lekin boshlang'ich bosqichidayoq yaxshi odat:

spring:
  jpa:
    hibernate:
      ddl-auto: validate

va Flyway migration yozish.

Development uchun:

Entity yozdingiz
Migration SQL yozdingiz
Application start qildingiz
Flyway migrationni bajardi
Hibernate validate qildi

Bu 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.sql
CREATE 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 true

Bu 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.sql
INSERT 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.sql

R__ 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
SQL

Masalan 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: true

Flyway 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.sql
CREATE 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 aniqlaydi

Lekin 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 mismatch

Bunday 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 -d

Lekin production’da bunday qilinmaydi.


30. Migration yozishda eng yaxshi amaliyotlar

1. Har bir o‘zgarish alohida fayl

Yomon:

V2__many_changes.sql

Ichida hamma narsa aralash.

Yaxshiroq:

V2__create_products_table.sql
V3__add_product_description.sql
V4__add_product_indexes.sql

2. 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: validate

4. 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 NULL

5. 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: update

Production uchun xavfli.

Yaxshiroq:

spring:
  jpa:
    hibernate:
      ddl-auto: validate

Xato 2: Migration fayl nomida bitta underscore

Yomon:

V1_init.sql

To‘g‘ri:

V1__init.sql

Xato 3: Bajarilgan migrationni edit qilish

Yomon:

V1__init.sql faylni production’dan keyin o‘zgartirish

To‘g‘ri:

V2__add_column.sql yaratish

Xato 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 NULL

Yaxshiroq:

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 fayl

33. Amaliy vazifa

Oldingi Product CRUD API loyihasiga Flyway qo‘shing.

1. Dependency qo‘shing

flyway-core
flyway-database-postgresql

2. Papka yarating

src/main/resources/db/migration

3. Migration fayllar

V1__create_categories_table.sql
V2__create_products_table.sql
V3__create_users_table.sql
V4__insert_initial_categories.sql

4. 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/migration

5. Tekshirish

Application start bo‘lganda database’da quyidagilar bo‘lsin:

categories
products
users
flyway_schema_history

Xulosa

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.