Spring

Flyway 사용법 (#2)

chanyoun 2025. 11. 15. 17:20

Flyway 사용법 (#2)

Flyway 사용법 (#1) 에서 대략적인 Flyway 사용방법을 다뤄 봤습니다.

이번 글에서는 Flyway 사용 중 자주 발생하는 문제와 해결 방법을 정리합니다.

 

  1. SQL 파일과 Entity 의 불일치 문제
  2. 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 스키마가 일치하므로 정상적으로 구동됩니다.

image-20251105220427388

실행결과 문제없이 잘 실행되는것을 볼수있습니다.

 

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;
}
스크린샷 2025-11-05 오후 10.06.09

 

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);
스크린샷 2025-11-05 오후 10.08.48

위 사진에서 보이는것 처럼 문제없이 실행이 됩니다.

 

이러한 한계를 극복하기위해 DB -> Entity 방향 검증을 위한 글을 다음에 써보겠습니다.

 

2. SQL 파일이 무한히 늘어나는 문제

Flyway는 마이그레이션을 버전 기반(V1__, V2__, …) 으로 관리합니다.

파일이 몇 개 수준일 때는 큰 문제가 없지만, 서비스가 장기 운영되면 마이그레이션 파일이 수백, 수천 개로 누적될 수 있습니다.

이럴 경우 유지보수성·빌드 시간·이전 버전 호환성 관리가 어려워집니다.

 

2.2 테스트 사전 준비

스크린샷 2025-11-05 오후 10.32.05

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)을 코드에서 제거하더라도 검증이 통과하도록 해야 합니다.

스크린샷 2025-11-11 오후 8.21.43

이를 위해 아래와 같이 설정합니다.

spring:
  flyway:
    enabled: true
    validate-on-migrate: true
    ignore-migration-patterns: "*:missing"
  • ignore-missing-migrations → 히스토리에 기록은 남아있지만 파일이 없는 버전(V1, V2)을 검증에서 무시합니다. → 따라서 코드에서 과거 파일을 삭제해도 검증 단계에서 실패하지 않습니다.
스크린샷 2025-11-11 오후 8.44.48스크린샷 2025-11-11 오후 8.45.54

따라서 더 이상 관리할 필요 없는 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 테이블을 비우거나 삭제했다고 가정합니다.

스크린샷 2025-11-15 오후 4.43.54

 

application.yml

  flyway:
    enabled: true
    baseline-on-migrate: true
    baseline-version: 1
스크린샷 2025-11-15 오후 4.46.17

이제 서버를 실행하면 위 처럼 history 테이블이 생성되고 BASELINE 이 기록됩니다.

이렇게 하면 기존 스키마 전체가 Flyway 기준의 “V1 적용 완료 상태”가 되며,

이후 컬럼 추가 등의 변경은 V2__...sql 버전부터 적용하면 됩니다.

 

V2__add_number_column.sql

ALTER TABLE member
ADD COLUMN number VARCHAR(255);
스크린샷 2025-11-15 오후 4.48.45

 

이처럼 baseline 을 기준으로 이후 버전들이 정상 적용됩니다.

 

2.4 결론

ignore-migration-patterns을 사용할 때

“히스토리는 그대로 두고, 과거 파일만 깔끔하게 치우고 싶을 때”

  • 이미 운영 DB에는 v1~v50 까지 기록이 있음
  • 하지만 repo에서는 v1~v50 파일을 삭제해도 Flyway가 에러 내지 않게 하고 싶음
  • DB는 유지, 히스토리는 유지
  • 새 DB를 Flyway로 처음부터 풀로 재현할 필요가 없는 경우

즉, 운영과 기존 히스토리는 유지하면서 과거 SQL을 정리하고 싶은 상황에서 사용합니다.

baseline 을 사용할 때

“이미 스키마가 있는 DB의 ‘지금 상태’를 새로운 시작 버전으로 선언하고 싶을 때”

  • 운영 DB를 비울 수 없음
  • 현재 스키마를 기준으로 “여기부터 V1이다” 라고 선언해야 함
  • Flyway 도입 시점, 스쿼시 후 새로운 기준점을 잡고 싶을 때
  • history 테이블을 비우거나 유실된 뒤 기준점을 다시 만들어야 할 때

즉, ‘기존 스키마를 건드리지 않고 버전의 시작점을 다시 설정해야 할 때’ baseline 을 사용합니다.