ddl-auto: update로 운영 DB를 관리하다가 컬럼 하나가 조용히 사라지는 경험, 한 번쯤 있으실 겁니다. JPA의 자동 DDL은 편하지만 "언제, 누가, 무엇을" 바꿨는지 기록이 남지 않습니다. 코드에는 Git이 있는데 DB 스키마에는 버전 관리가 없는 셈이죠. 이 공백을 메우는 도구가 바로 Flyway입니다.
Flyway가 하는 일
Flyway는 SQL 마이그레이션 파일을 버전 순서대로 실행하고, 실행 이력을 flyway_schema_history 테이블에 기록합니다. 애플리케이션이 시작될 때 아직 적용되지 않은 버전만 골라 실행하므로, 어느 환경에서든 스키마가 동일한 상태로 수렴합니다.
핵심 개념은 세 가지입니다.
- Versioned Migration (
V): 한 번만 실행되는 변경.V1__create_member.sql처럼 버전 번호를 갖습니다. - Repeatable Migration (
R): 파일 체크섬이 바뀔 때마다 재실행. 뷰나 프로시저 정의에 적합합니다. - 체크섬 검증: 이미 적용된 파일이 수정되면 기동 시점에 에러를 내며 멈춥니다. 스키마 이력의 무결성을 지키는 안전장치입니다.
Spring Boot 적용하기
Gradle(Kotlin DSL) 기준 의존성은 두 줄이면 됩니다. MariaDB/MySQL은 전용 모듈이 별도로 필요하다는 점만 주의하세요.
// build.gradle.kts
dependencies {
implementation("org.flywaydb:flyway-core")
implementation("org.flywaydb:flyway-mysql") // MariaDB/MySQL 필수
}
설정은 application.yml에서 JPA의 DDL 생성을 끄고 검증만 맡기는 것이 핵심입니다.
spring:
jpa:
hibernate:
ddl-auto: validate # 스키마 생성은 Flyway, JPA는 검증만
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true # 기존 운영 DB에 처음 도입할 때
첫 마이그레이션 파일을 src/main/resources/db/migration/V1__create_member.sql로 만듭니다.
-- V1__create_member.sql
CREATE TABLE member (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
role VARCHAR(20) NOT NULL DEFAULT 'USER',
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
이후 컬럼 추가가 필요하면 기존 파일을 고치는 게 아니라 새 버전을 추가합니다.
-- V2__add_member_nickname.sql
ALTER TABLE member ADD COLUMN nickname VARCHAR(30) NULL AFTER email;
애플리케이션을 실행하면 로그에 적용 내역이 출력되고, flyway_schema_history 테이블에서 버전·체크섬·실행 시각을 확인할 수 있습니다.
실무 팁과 주의사항
1. 적용된 파일은 절대 수정하지 않는다. 체크섬 불일치로 기동이 실패합니다. 오타가 있어도 새 버전(V3)으로 수정하는 것이 원칙입니다. 로컬에서 이미 꼬였다면 ./gradlew flywayRepair로 체크섬을 재계산할 수 있지만, 운영에서는 신중해야 합니다.
2. 파일명 규칙: 언더스코어 두 개. V1_create.sql(하나)은 인식되지 않아 조용히 무시됩니다. V1__create.sql이 맞습니다. 의외로 가장 흔한 실수입니다.
3. 기존 운영 DB 도입은 baseline부터. 이미 테이블이 있는 DB에는 baseline-on-migrate: true를 켜고 현재 상태를 V1(baseline)으로 선언한 뒤, 이후 변경만 V2부터 관리합니다.
4. 테스트 환경 분리. H2로 테스트한다면 MariaDB 전용 문법(AFTER, ENGINE=InnoDB 등)이 깨질 수 있습니다. spring.flyway.locations를 프로파일별로 나누거나, Testcontainers로 실제 MariaDB를 띄우는 편이 안전합니다.
5. 롤백은 공짜가 아니다. 무료 버전에는 undo 기능이 없습니다. 되돌림이 필요하면 보상 마이그레이션(예: V3__drop_nickname.sql)을 새로 작성하는 방식으로 전진만 합니다. 그래서 파괴적 변경(컬럼 삭제 등)은 "컬럼 추가 → 코드 전환 → 다음 배포에서 삭제"처럼 단계를 나누는 습관이 중요합니다.
마무리
Flyway를 도입하면 스키마 변경이 코드 리뷰의 대상이 되고, 신규 환경 구축이 ./gradlew bootRun 한 번으로 끝납니다. ddl-auto: update의 편리함과 이별하는 대신, 운영 DB에 대한 예측 가능성을 얻는 거래입니다. 개인 프로젝트라도 배포를 염두에 둔다면 첫 테이블부터 Flyway로 시작하는 것을 권합니다.
'Programming > Database' 카테고리의 다른 글
| 낙관적 락 vs 비관적 락, 재고 차감에서 뭘 써야 하나 (0) | 2026.07.23 |
|---|---|
| 인덱스를 타지 않는 쿼리, 원인과 점검 (0) | 2026.07.16 |
| MariaDB vs MySQL 차이와 선택 기준 (0) | 2026.07.10 |
| MariaDB 버전 선택 가이드 (0) | 2026.07.08 |
| MariaDB 복합 인덱스로 느린 목록 조회 개선하기 (0) | 2026.07.01 |