Flyway 사용법 (#2)
Flyway 사용법 (#1) 에서 대략적인 Flyway 사용방법을 다뤄 봤습니다.
이번 글에서는 Flyway 사용 중 자주 발생하는 문제와 해결 방법을 정리합니다.
- SQL 파일과 Entity 의 불일치 문제
- Flyway SQL 파일이 무한히 늘어나는 문제
1. SQL 파일과 Entity 의 불일치 문제
1.1 문제 개요
Flyway는 SQL 기반으로 DB 스키마를 관리합니다.
하지만 JPA Entity는 코드 기반으로 스키마를 정의하기 때문에, 두 구조가 항상 일치한다는 보장이 없습니다.
1.2 ddl-auto: validate 설정
Entity 구조가 DB 스키마와 일치하는지 자동으로 확인할 수 있습니다.
spring:
jpa:
hibernate:
ddl-auto: validate
이 설정을 적용하면 애플리케이션 실행 시 다음이 수행됩니다.
| 케이스 | 결과 |
|---|---|
| Entity 필드가 DB에 없음 | 예외 발생 |
1.3 테스트 환경 구성
Member Entity
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String nickname;
@CreationTimestamp
private LocalDateTime createdAt;
}
V1__init.sql
CREATE TABLE `member`
(
`id` BIGINT NOT NULL AUTO_INCREMENT,
`nickname` VARCHAR(100) NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo
username: root
password: 1234
jpa:
hibernate:
ddl-auto: validate
flyway:
enabled: true
baseline-on-migrate: true
1.4 검증 결과
위 설정 상태로 애플리케이션을 실행하면 Entity와 SQL 스키마가 일치하므로 정상적으로 구동됩니다.
실행결과 문제없이 잘 실행되는것을 볼수있습니다.
1.5 불일치 발생 시 예외 확인
만약 Member Entity 에 Email 컬럼을 아래와 같이 추가후 실행하면 오류가 나는것또한 볼수있습니다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String nickname;
@Column(nullable = false, length = 50)
private String email;
@CreationTimestamp
private LocalDateTime createdAt;
}
1.6 한계
앞서 살펴본 것처럼 ddl-auto: validate 옵션을 사용하면
Entity → DB 방향의 불일치(즉, Entity에는 존재하지만 DB에는 없는 컬럼)는 감지할 수 있습니다.
하지만 그 반대 방향, 즉 DB → Entity 방향의 불일치는 검증할 수 없습니다.
예를 들어, 아래와 같이 Flyway를 통해 DB에만 컬럼을 추가하더라도 애플리케이션은 아무런 오류 없이 실행됩니다
V2__add_email_column.sql
ALTER TABLE `member`
ADD COLUMN `email` VARCHAR(255);
위 사진에서 보이는것 처럼 문제없이 실행이 됩니다.
이러한 한계를 극복하기위해 DB -> Entity 방향 검증을 위한 글을 다음에 써보겠습니다.
2. SQL 파일이 무한히 늘어나는 문제
Flyway는 마이그레이션을 버전 기반(V1__, V2__, …) 으로 관리합니다.
파일이 몇 개 수준일 때는 큰 문제가 없지만, 서비스가 장기 운영되면 마이그레이션 파일이 수백, 수천 개로 누적될 수 있습니다.
이럴 경우 유지보수성·빌드 시간·이전 버전 호환성 관리가 어려워집니다.
2.2 테스트 사전 준비
3개의 SQL 파일을 만들어두고 현재 Flyway는 V3 SQL까지 적용이 된 상태입니다.
Flyway는 과거 버전의 모든 SQL 파일을 이력으로 관리합니다. 따라서 이후 버전(V4__...)을 추가해도 V1부터 순차적으로 실행 및 검증 대상에 포함됩니다.
즉 Flyway 의 기본동작은 아래와 같습니다.
| 상황 | Flyway 동작 |
|---|---|
| DB에는 V1~V3 기록이 있음 | 정상 |
| 코드에서 V1, V2 파일이 사라짐 | missing migration 에러 |
| 코드의 V1, V2 SQL 내용이 변경됨 | checksum mismatch 에러 |
하지만 시간이 지나면
- 이미 오래전에 반영된 마이그레이션 SQL을 더 이상 관리할 필요가 없고
- 새 개발자가 프로젝트를 받아도 과거 SQL을 일일이 살펴볼 필요가 없는 상황이 됩니다.
2.2 ignore-migration-patterns
application.yml
spring:
flyway:
enabled: true
validate-on-migrate: true
ignore-migration-patterns: "*:missing"
| 상황 | 기본 동작 | ignore-migration-patterns 적용 시 |
|---|---|---|
| DB에는 V1, V2 기록 있음, 코드에서 V1, V2 파일 삭제 | missing migration 에러 | 무시하고 통과 |
| DB에는 V2 기록 있음코드의 V2 내용을 수정 | checksum mismatch 에러 | 여전히 에러 발생 |
즉, ignore-migration-patterns 옵션은 파일이 “없어진(missing)” 상황만 무시하며, 내용 변경(checksum mismatch)은 절대 허용하지 않습니다.
따라서 ignore-migration-patterns 은 이미 DB에는 적용되었지만, 더 이상 소스코드에 보관할 필요 없는 과거 SQL 파일들을 안전하게 삭제하고 싶을 때 사용할 수 있습니다.
2.2.1 ignore-migration-patterns 테스트
기존 DB에는 flyway_schema_history가 존재하므로, 과거 파일(V1, V2)을 코드에서 제거하더라도 검증이 통과하도록 해야 합니다.
이를 위해 아래와 같이 설정합니다.
spring:
flyway:
enabled: true
validate-on-migrate: true
ignore-migration-patterns: "*:missing"
ignore-missing-migrations→ 히스토리에 기록은 남아있지만 파일이 없는 버전(V1,V2)을 검증에서 무시합니다. → 따라서 코드에서 과거 파일을 삭제해도 검증 단계에서 실패하지 않습니다.

따라서 더 이상 관리할 필요 없는 SQL들을 삭제하고도 기존 DB를 유지해야 한다면 ignore-migration-patterns 를 사용할 수 있습니다.
2.3 baseLine
baseline 은 이미 DB에 스키마가 존재할 때, “이 시점을 특정 버전(Vx)의 기준점으로 삼겠다”는 의미로 사용합니다.
즉 baseline 을 통하여 현재 스키마 상태를 버전 X부터 시작한 것으로 간주하고,
그 이후 버전부터 Flyway로 관리하겠다는 뜻입니다.
예를 들어 현재 V1~V3 까지 수동으로(또는 기존 Flyway로) 적용된 DB가 있고,
이제 V1~V3 를 하나로 묶어 새로운 V1로 시작하고 싶다면 baseline 을 사용할 수 있습니다.
2.3.1 baseLine 활용
baseline 적용을 위해 flyway_schema_history 테이블을 비우거나 삭제했다고 가정합니다.
application.yml
flyway:
enabled: true
baseline-on-migrate: true
baseline-version: 1
이제 서버를 실행하면 위 처럼 history 테이블이 생성되고 BASELINE 이 기록됩니다.
이렇게 하면 기존 스키마 전체가 Flyway 기준의 “V1 적용 완료 상태”가 되며,
이후 컬럼 추가 등의 변경은 V2__...sql 버전부터 적용하면 됩니다.
V2__add_number_column.sql
ALTER TABLE member
ADD COLUMN number VARCHAR(255);
이처럼 baseline 을 기준으로 이후 버전들이 정상 적용됩니다.
2.4 결론
ignore-migration-patterns을 사용할 때
“히스토리는 그대로 두고, 과거 파일만 깔끔하게 치우고 싶을 때”
- 이미 운영 DB에는 v1~v50 까지 기록이 있음
- 하지만 repo에서는 v1~v50 파일을 삭제해도 Flyway가 에러 내지 않게 하고 싶음
- DB는 유지, 히스토리는 유지
- 새 DB를 Flyway로 처음부터 풀로 재현할 필요가 없는 경우
즉, 운영과 기존 히스토리는 유지하면서 과거 SQL을 정리하고 싶은 상황에서 사용합니다.
baseline 을 사용할 때
“이미 스키마가 있는 DB의 ‘지금 상태’를 새로운 시작 버전으로 선언하고 싶을 때”
- 운영 DB를 비울 수 없음
- 현재 스키마를 기준으로 “여기부터 V1이다” 라고 선언해야 함
- Flyway 도입 시점, 스쿼시 후 새로운 기준점을 잡고 싶을 때
- history 테이블을 비우거나 유실된 뒤 기준점을 다시 만들어야 할 때
즉, ‘기존 스키마를 건드리지 않고 버전의 시작점을 다시 설정해야 할 때’ baseline 을 사용합니다.
'Spring' 카테고리의 다른 글
| Spring WebSocket(STOMP) 통합 테스트 정리 (0) | 2025.10.17 |
|---|---|
| Flyway 사용법 (#1) (0) | 2025.09.25 |
| JPQL 실행 시 Flush와 영속성 컨텍스트 동작 확인 (0) | 2024.07.22 |
| API 통신 시 null 값 처리: 포함 vs. 미포함의 장단점 (0) | 2024.07.22 |
| JPA에서 단방향 및 양방향 일대일 관계의 외래키 처리와 지연 로딩 문제 (1) | 2024.07.22 |







