Spring REST API & Data JPA
43/46
Bài 43 / 46~12 phútMigration & CapstoneLộ trình · chặng 17/21Miễn phí… lượt xem

Flyway Migration: Quản Trị Phiên Bản Schema Như Mã Nguồn

Thiết lập Flyway với Spring Boot, quản lý bảng flyway_schema_history, tính bất biến của checksum và cơ chế baseline cho cơ sở dữ liệu legacy.

TL;DR: Flyway biến schema cơ sở dữ liệu thành các artifact có thể quản lý bằng Git: mỗi thay đổi là một file SQL có định dạng V<version>__<description>.sql, được thực thi đúng một lần duy nhất theo thứ tự và lưu checksum vào bảng flyway_schema_history. Sau khi đã apply, file migration trở thành bất biến để bảo toàn tính nhất quán giữa các môi trường. Sử dụng ddl-auto: validate kết hợp cùng Flyway là chuẩn mực vàng cho production.

Vì sao ddl-auto=update bị cấm trên môi trường Production?

Cấu hình ddl-auto: update của Hibernate tiềm ẩn nhiều rủi ro phá hủy dữ liệu:

  • Không có lịch sử phiên bản: Không thể biết database đang ở trạng thái nào.
  • Không thể DROP hoặc RENAME: Khi đổi tên trường Java, Hibernate chỉ thêm cột mới và bỏ hoang cột cũ, gây rác schema.
  • Xung đột đa tiến trình (Race Condition): Khi triển khai nhiều pod khởi động đồng thời, các pod cùng chạy ALTER TABLE gây khóa bảng deadlock.

Flyway giải quyết triệt để vấn đề này theo 3 nguyên lý: Versioned (có số phiên bản tuần tự), Reproducible (chạy trên bất kỳ máy nào đều cho kết quả giống hệt nhau), và Audited (ghi vết rõ ràng).

Các khái niệm cốt lõi của Flyway gồm những gì?

1. Quy tắc đặt tên file Migration

Flyway phát hiện các file migration dựa trên tên file trong thư mục src/main/resources/db/migration/:

V<version>__<mo_ta>.sql
  ^         ^^
  |         Bat buoc 2 dau gach duoi (Double Underscore)
  So version (1, 2, 2.1, 20260501...)
Bẫy một dấu gạch dưới

Tên file V1_init.sql (1 dấu gạch dưới) sẽ bị Flyway bỏ qua âm thầm mà không có cảnh báo nào, khiến schema không được tạo và Hibernate báo lỗi thiếu bảng.

2. Bảng theo dõi flyway_schema_history

Khi khởi chạy, Flyway tự động tạo bảng flyway_schema_history làm "sổ cái" theo dõi:

SQL
SELECT installed_rank, version, description, checksum, success
FROM flyway_schema_history;

Ba file migration trên đĩa đối chiếu với hai row trong bảng flyway_schema_history: V1 và V2 đã có row nên bị bỏ qua, còn V3 chưa có row nào nên là chênh lệch duy nhất và được apply

Flyway so sánh danh sách file trên đĩa với bảng history:

  • File nào đã có row thành công: Bỏ qua (Idempotent).
  • File nào chưa có: Thực thi tuần tự và ghi nhận checksum tương ứng.

Tại sao mã Checksum bắt buộc phải bất biến?

Mỗi file migration khi chạy xong sẽ được tính toán một mã băm CRC32 checksum lưu vào database.

Nếu bạn sửa đổi dù chỉ một dấu cách trong file V1__init_schema.sql sau khi đã deploy, Flyway sẽ phát hiện mã checksum tính toán lại bị lệch so với mã đã lưu trong history và lập tức từ chối khởi động ứng dụng (Fail-Fast):

Cùng một file V2 nhưng env A apply bản gốc còn env B apply bản đã sửa: hai môi trường ghi hai checksum khác nhau và có schema khác nhau, trong khi history của cả hai đều nói version bằng 2

Nguyên tắc vàng: Không bao giờ sửa file migration cũ đã merge vào branch chính. Mọi sửa đổi, vá lỗi phải được viết trong một file migration mới (ví dụ: V2__fix_column.sql).

Cấu hình chuẩn mực trong Spring Boot ra sao?

Khai báo dependency trong pom.xml:

XML
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
</dependency>

Cấu hình trong application.yml:

YAML
spring:
  flyway:
    enabled: true
    locations: classpath:db/migration
    validate-on-migrate: true # Kiem tra checksum nghiem ngat khi boot

  jpa:
    hibernate:
      ddl-auto: validate # Hibernate chi validate entity khop voi schema Flyway

Tích hợp Flyway vào Cơ sở dữ liệu cũ (Baseline) như thế nào?

Nếu database production đã có sẵn 20 bảng từ trước khi đưa Flyway vào dự án:

  • Nếu để mặc định, Flyway không thấy bảng history nên sẽ chạy lại V1__init_schema.sql và gây lỗi relation "projects" already exists.
  • Giải pháp: Bật tính năng Baseline.
YAML
spring:
  flyway:
    baseline-on-migrate: true # Tu dong danh dau moc ban dau neu DB chua co history
    baseline-version: 1       # Coi nhu DB hien tai da o version 1

Khi đó:

  • Trên Production: Flyway chèn một bản ghi BASELINE version 1 vào history mà không chạy file V1, sau đó chỉ thực thi các file từ V2 trở đi.
  • Trên môi trường Dev/Test mới: Database trống hoàn toàn nên Flyway sẽ chạy tuần tự từ V1 đến hết, đảm bảo cả hai môi trường đạt cùng schema cuối cùng.

Những cạm bẫy phổ biến cần tránh là gì?

  1. Đặt sai tên file (1 dấu gạch dưới): Flyway bỏ qua file migration mà không hề báo lỗi cú pháp.
  2. Dùng song song ddl-auto=update với Flyway: Gây ra xung đột tranh chấp thay đổi cấu trúc bảng giữa Hibernate và Flyway.
  3. Sửa file migration đã commit lên Git: Làm hỏng tính toàn vẹn checksum và khiến toàn bộ cluster không thể khởi động.

Tự kiểm tra kiến thức

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Tại sao Flyway lại kiểm tra nghiêm ngặt mã checksum và từ chối khởi động ứng dụng nếu phát hiện file migration cũ bị chỉnh sửa?
  2. Q2
    Định dạng tên file nào sau đây là hợp lệ để Flyway nhận diện được một file Versioned Migration?
  3. Q3
    Khi triển khai hệ thống trên Kubernetes với 10 pod cùng khởi động đồng thời, Flyway ngăn chặn xung đột chạy migration bằng cách nào?
  4. Q4
    Cặp cấu hình chuẩn mực nhất giữa Hibernate và Flyway trên môi trường Production là gì?
  5. Q5
    Tính năng 'baseline-on-migrate: true' trong Flyway giải quyết bài toán nào?

Bài tiếp theo: Chiến Lược Migration: Zero-Downtime và Mô Hình Expand-Contract

Bài này có giúp bạn hiểu bản chất không?

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Lộ trình Junior Java Backend Developer

Chặng 17/21 · Database migration (Flyway) — bài 1/2 của chặng

Thảo luận & góp ý

Hỏi đáp về bài này

Bài tiếp theo

Chiến Lược Flyway: Zero-Downtime và Expand-Contract