34 - Database Migration ด้วย Flyway
เป้าหมายของบท
Section titled “เป้าหมายของบท”บทนี้จะเปลี่ยนวิธีจัดการ schema จาก Hibernate ddl-auto=update ไปใช้ Flyway migration
หลังจบบทนี้ผู้อ่านควรเข้าใจ:
- ทำไม
ddl-auto=updateไม่เหมาะกับ production - Flyway migration file ตั้งชื่ออย่างไร
- เก็บ migration ไว้ที่ไหน
- เปลี่ยน
ddl-autoเป็นvalidateอย่างไร - migration table
flyway_schema_historyใช้ทำอะไร
ปัญหาของ ddl-auto=update
Section titled “ปัญหาของ ddl-auto=update”ตอนเรียนเราใช้:
spring.jpa.hibernate.ddl-auto=updateเพราะสะดวก แต่ production ไม่ควรใช้ เพราะ:
- schema เปลี่ยนอัตโนมัติโดยไม่มี review
- rollback ยาก
- ไม่เห็น history ชัดเจนว่า table เปลี่ยนเมื่อไร
- deploy หลาย environment แล้วเสี่ยง schema ไม่ตรงกัน
งานจริงควรใช้ migration script ที่ถูก commit เข้า Git
เพิ่ม dependency
Section titled “เพิ่ม dependency”dependencies { implementation 'org.springframework.boot:spring-boot-starter-flyway' implementation 'org.flywaydb:flyway-database-postgresql'}สำหรับ Spring Boot 4 ให้ใช้ spring-boot-starter-flyway เพื่อให้ auto-configuration ของ Flyway ถูกโหลดด้วย
ถ้าใส่แค่ flyway-core migration จะไม่ถูกรันตอน start application
ตั้งค่า application.properties
Section titled “ตั้งค่า application.properties”spring.jpa.hibernate.ddl-auto=validatespring.flyway.enabled=truespring.flyway.locations=classpath:db/migrationvalidate หมายถึง Hibernate จะตรวจว่า entity กับ table เข้ากันได้ แต่จะไม่สร้าง table เอง
สร้าง migration แรก
Section titled “สร้าง migration แรก”สร้างไฟล์:
src/main/resources/db/migration/V1__create_users_table.sqlตัวอย่าง:
CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, role VARCHAR(20) NOT NULL, status VARCHAR(20) NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL);สร้าง audit logs:
src/main/resources/db/migration/V2__create_audit_logs_table.sqlCREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, action VARCHAR(100) NOT NULL, actor_id BIGINT NOT NULL, target_user_id BIGINT NOT NULL, old_value VARCHAR(100), new_value VARCHAR(100), created_at TIMESTAMP NOT NULL);Naming convention
Section titled “Naming convention”รูปแบบ:
V<version>__<description>.sqlตัวอย่าง:
V1__create_users_table.sqlV2__create_audit_logs_table.sqlV3__add_last_login_at_to_users.sqlต้องมี underscore 2 ตัวระหว่าง version กับ description:
V1__create_users_table.sqlไม่ใช่:
V1_create_users_table.sqlflyway_schema_history
Section titled “flyway_schema_history”เมื่อรัน application Flyway จะสร้าง table:
flyway_schema_historytable นี้เก็บว่า migration ไหนถูกรันแล้ว ถ้า V1 รันไปแล้ว Flyway จะไม่รันซ้ำ
เปลี่ยน schema ในอนาคต
Section titled “เปลี่ยน schema ในอนาคต”ห้ามแก้ migration เก่าที่รันไปแล้วใน environment อื่น
ถ้าต้องเพิ่ม column ให้สร้างไฟล์ใหม่:
V3__add_last_login_at_to_users.sqlALTER TABLE usersADD COLUMN last_login_at TIMESTAMP;แบบฝึกหัดท้ายบท
Section titled “แบบฝึกหัดท้ายบท”- เพิ่ม Flyway dependency
- เปลี่ยน
ddl-autoเป็นvalidate - สร้าง
V1__create_users_table.sql - สร้าง
V2__create_audit_logs_table.sql - รัน application แล้วตรวจ
flyway_schema_history - เพิ่ม migration ใหม่เพื่อเพิ่ม column
last_login_at