0. 서론
이전에 Flyway를 사용해서 DB 형상 관리를 하면, 좀 더 개발에 집중할 수 있다고 생각해 도입한 기억이 있습니다. 다만 소수 인원이었기에 단순히 배포할 때, 실행해야 할 쿼리가 누락되는 걸 방지하기 위한 용도로만 사용했습니다. 이후 업무를 하면서 DDL, DML 쿼리가 생각보다 자주 발생하는 것을 느끼고 이를 팀원끼리 매번 공유하기 어려워, Flyway를 도입해 그 시간을 단축하면 좋겠다는 생각이 들었습니다. 그리하여 도입 전 Flyway에 대해 알아보고 정확히 알아보기 위해 이번 글을 작성하고자 합니다.
1. Flyway 알아보기
1.1 Flyway란?
- Flyway는 DB 마이그레이션 툴로, DB 형상관리를 위한 도구
- Git을 통해 코드 형상 관리를 하듯, Flyway를 사용해 다른 사람들과 DB 형상관리를 할 수 있음
1.2 Flyway를 통해 얻을 수 있는 장점
- DB 형상관리를 통해 수동으로 쿼리를 공유하고 실행하지 않아 개발에 집중 가능
- 이전에 실행되었던 쿼리들의 히스토리를 쉽게 관리할 수 있음
- DB 마이그레이션 자동화
1.3 DB 마이그레이션이 왜 필요한가?
- 코드 부분은 현재 Git과 같은 형상관리 툴로 관리가 잘 이루어지고 있음
- 하지만 DB 상태에 대해서는 정확한 관리가 되고 있지 않음
- 그렇기 때문에 각각의 환경에서 DB 관리를 수동으로 진행하거나 누락되는 경우가 종종 생김
- 이때 Flyway를 사용해서 DB도 코드처럼 형상관리를 통해, 각각 환경에 맞게끔 DB 마이그레이션을 진행해 생산성을 높일 수 있음
2. Spring Boot Flyway 적용
2.1 개발환경
- Spring Boot 3.3.6, Java 17, MySQL 8.0.36
2.2 Flyway 설정
Flyway Gradle 설정
- Gradle Task에서 flyway를 사용하기 위해 plugins 부분을 아래와 같이 추가
plugins {
id "org.flywaydb.flyway" version "11.0.0"
}
dependencies {
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
}
flyway {
url = 'jdbc:mysql://localhost:3306/beer?useSSL=false&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true'
user = 'root'
password = '1234'
baselineVersion = 1
outOfOrder = true
}
Flyway 스크립트 파일 기본 위치 및 설정
- Flyway가 스크립트를 실행하기 위한 기본 파일 위치는 main/resources/db/migration
- 다만 application.yml에서 spring.flyway.locations에 value를 설정해 위치를 변경할 수 있음
2.3 Flyway Schema History
- flyway를 통해 스키마를 관리할 때 어떤 변경 내역들이 존재했는지 확인할 수 있는 테이블
- 작성했던 스크립트를 기반으로 version, type, description과 같은 데이터가 저장
- 스크립트 실행 시간, 성공 여부 또한 확인할 수 있음
create table if not exists beer.flyway_schema_history
(
installed_rank int not null
primary key,
version varchar(50) null,
description varchar(200) not null,
type varchar(20) not null,
script varchar(1000) not null,
checksum int null,
installed_by varchar(100) not null,
installed_on timestamp default CURRENT_TIMESTAMP not null,
execution_time int not null,
success tinyint(1) not null
);
2.4 Flyway 컨벤션
Flyway 스크립트 네이밍
- flyway 스크립트 네이밍 Prefix + Version + Separator + Description + suffix으로 조합됨
- 조합한 네이밍 규칙은 아래와 같습니다
Prefix
- Prefix는 크게 V(Versioned), U(Undo), R(Repeatable)로 구분
- V(Versioned)는 현재 버전을 새로운 버전으로 업데이트할 때 사용
- U는 현재 버전을 이전 버전으로 되돌리고 싶은 경우
- R은 버전 관련없이 매번 실행되어야 할 때
Version
- version은 dots나 underscore를 통해 자유롭게 작성할 수 있음
- 다만 version을 작성할 때는 이전 버전보다 높게 작성해야 함
- 예를 들어 version을 1.0 이후에 1.1이나 2.0과 같이 작성해야 Flyway가 스크립트를 적용함
Seperator, Description, Suffix
- Seperator는 무조건 언더스코어를 두 번 적어서 분리해야 함
- Description은 스크립트 내용을 설명하도록 작성할 수 있고, underscore나 space로 단어들을 분리할 수 있음
- Suffix는 단순히 sql 파일임을 명시하면 됨
3. Spring Boot Flyway 활용
3.1 Prefix에 따른 스크립트 작성
V(Versioned)
V1 적용
- V1 Script에서 테이블을 생성하도록 실행
- flyway schema history를 확인했을 때 정상적으로 실행된 것을 확인
V1 Migration 이후 V0.1 Migration 적용 여부 확인
- V1로 Migration을 진행한 후 아래와 같이 V0.1 script를 만들어 어플리케이션 서버를 실행
- 실행 콘솔을 확인해 보면 Version이 더 낮아서 무시되는 script가 있음을 flyway가 검증하는 것을 확인
R(Repetable)
- 어플리케이션 서버를 실행할때마다 스크립트가 실행되는 것을 확인(R__insert_test_data.sql이 지속적으로 추가됨)
4. 여러 DB에서 Flyway 적용
하나의 DB가 아닌 여러 개의 DB나 Schema를 사용하는 경우에는 어떻게 Flyway를 적용할 수 있는지에 대해서도 알아보았습니다.
4.1 Datasource 설정
- 아래와 같은 DB에 Schema를 다르게 하여 2개의 DataSource를 빈으로 등록
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
public DataSource primaryDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/beer?useSSL=false&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true");
hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariConfig.setUsername("root");
hikariConfig.setPassword("1234");
return new HikariDataSource(hikariConfig);
}
@Bean(name = "secondaryDataSource")
public DataSource secondaryDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true");
hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariConfig.setUsername("root");
hikariConfig.setPassword("1234");
return new HikariDataSource(hikariConfig);
}
}
4.2 Flyway 설정 및 migrate 실행
- 이후 각 Schema에 맞게끔 flyway가 동작하게끔 Datasource, script locations, table을 설정
- 어플리케이션 서버를 실행시킬 때 Migrate 되도록 migrate() 메서드 호출
@Configuration
public class FlywayConfig {
@Primary
@Bean(name = "primaryFlyway")
public Flyway primaryFlyway(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
Flyway flyway = Flyway.configure()
.dataSource(primaryDataSource)
.baselineOnMigrate(true)
.baselineVersion("0")
.locations("classpath:db/migration/primary")
.table("flyway_schema_history_primary")
.load();
flyway.migrate();
return flyway;
}
@Bean(name = "secondaryFlyway")
public Flyway secondaryFlyway(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
Flyway flyway = Flyway.configure()
.dataSource(secondaryDataSource)
.baselineOnMigrate(true)
.baselineVersion("0")
.locations("classpath:db/migration/secondary")
.table("flyway_schema_history_secondary")
.load();
flyway.migrate();
return flyway;
}
}
4.3 Flyway Script 실행 확인
- 어플리케이션을 실행시킨 후 각 스키마에 Flyway_schema_history가 생성되어 있음을 확인
맺음말
앞으로 어떻게 Flyway를 적용하고 형상관리를 할지는 팀원들과 규칙을 정해서 사용할 필요가 있다고 느꼈습니다. 그리고 다음과 같은 점들을 배울 수 있었습니다.
- Flyway 기본적인 사용법 및 사용이유
- 여러 DB에서 Flyway 적용 및 관리
읽어주셔서 감사합니다.
'Spring' 카테고리의 다른 글
Gradle 설정 알아보기 (2편) (0) | 2025.02.23 |
---|---|
Gradle 설정 알아보기 (1편) (0) | 2025.02.16 |
환경변수가 있었는데요? 없었습니다 (2) | 2024.11.09 |
JPA 양방향 매핑 탈출기 (0) | 2024.10.27 |
@PathVariable 엔드포인트 매핑 원리 (1) | 2024.10.12 |