
Flyway 공식 Github: https://github.com/flyway/flyway
Flyway: Flyway는데이터베이스 마이그레이션 도구(Database Migration Tool)이다. 쉽게 말해서, DB 스키마 버전을 코드로 관리하게 해주는 형상 관리 도구(Version Control System)이라고 생각하면 된다.
※ Database Migration: 특정 데이터베이스에서 다른 데이터베이스로 이동하는 것이다. Flyway에서는 데이터베이스에서 일어나는 모든 변경을 의미한다.

소스 코드의 변경 감지와 형상 관리는 깃허브에서 진행되는 것과 같이 DB의 변경 감지와 형상 관리는 Flyway에서 일어난다.
※ 형상 관리: 소프트웨어의 변경 사항을 체계적으로 추적하고 통제하는 것
개발 도중에 DB의 스키마 변경이 일어나는 경우는 종종 생겨난다. 예를 들어 특정 테이블에 새로운 컬럼을 추가한다고 가정해보자. 이런 경우에는 Flyway 적용 전에는 보통 다음과 같은 두 가지 방식을 많이 사용하였을 것이다.
1. jpa의 ddl-auto 사용
spring:
jpa:
hibernate:
ddl-auto: create or update
보통 가장 흔히 사용한 방법은 ddl-auto로 JPA에서 자동으로 변경된 테이블을 새로 생성하거나 수정하는 방식이었을 것이다. 하지만 ddl-auto 자체가 실무에서는 많이 지양되는 기술이고 create 옵션을 사용하면 기존 테이블에 있던 이전 데이터까지 전부 초기화해버리기 때문에 배포 환경에서 절대 사용불가능하다.
또한 update 옵션 역시 위험하기는 마찬가지이다. 새로운 엔티티나 테이블을 추가하는 것까지는 큰 문제가 발생하지 않는다.
하지만 예를 들어 username → name으로 변경하면 Hibernate는 username 컬럼이 사라졌다고 판단 → DROP COLUMN 후 ADD COLUMN name을 시도하여 해당 컬럼의 기존 데이터가 전부 날아갈 수 있고 컬럼의 데이터 타입을 String → int으로 바꾸어도 타입이 바뀐 것을 확실히 인식 못하거나 DB마다 다르게 동작할 가능성이 존재한다. 또한 Hibernate는 제약 조건 변경에 있어 매우 조심스럽고 보수적으로 판단하기 때문에 nullable=true → nullable=false 바꿔도 ALTER TABLE을 안 하는 것처럼 반영하지 않거나 애매하게 처리할 수 있다.

2. 각 배포 환경(local, dev, prod 등)을 일일이 돌아다니며 직접 schema 수정
이 방법은 굳이 필자가 말 안 해도 매번 사용하기에는 매우 비효율적이고 위험한 방법이다...

local에서 h2를 사용하여 개발하고 개발이 완료되면 MySQL을 사용하는 dev로 merge하고 1주일에 한 번씩 MySQL을 사용하는 deploy로 merge한다고 가정해보자.

Crew 테이블에 주소 저장 로직을 추가해달라는 요청을 받아

address 컬럼을 추가하고 주소 저장 로직까지 작성하여

테스트까지 성공하고 dev 브랜치에 merge하고 deploy DB에 컬럼을 추가하려고 했지만

회의로 인해 deploy DB에 컬럼을 추가하는 것을 까먹었다고 가정해보자.

이로 인하여 배포 과정에서 주소 저장 로직에 실패하여 오류가 발생하였다.
하지만 ddl-auto와 직접 수작업으로 컬럼 추가 대신에 만약 Flyway를 사용하였다면 어떻게 되었을까??

Flyway를 사용하였다면 엔티티에 address 컬럼을 추가하고 비즈니스 로직에 주소 저장 로직 코드를 추가한 후에 직접 deploy DB에 컬럼을 추가하는 것이 아니라 V2__add_address.sql 파일을 만들고 해당 파일에 address 컬럼을 추가하는 쿼리를 작성해놓으면 배포가 될 때 자동으로 Flyway가 DB 변경 사항을 적용시켜줌으로써 장애가 발생하지 않는다.


※ 이처럼 개발 과정 중에 빈번이 일어나는 DB의 변경을 효율적이고 안전하고 자동으로 처리하고 여러 편의성으로 인하여 Flyway를 사용한다.
Migrate: 데이터베이스의 변경Baseline: 비어있지 않은 기존 데이터베이스에서 Flyway 적용
Info: 데이터베이스의 변경 이력 저장
Repair: 실패한 마이그레이션 파일을 복구
Validate: Flyway를 복구할 때 데이터베이스 적용 가능 여부 확인
Undo: 최근에 적용되었던 마이그레이션 파일 적용 취소
Clean: 데이터베이스 초기화
이 중 비중이 높은 Migrate, Baseline, Info 3가지 특성에 대해 자세히 살펴보자.

비어있는 DB에서 Flyway를 사용하여 Crew라는 테이블을 만들기 위해

V1__init.sql 파일을 만들고 파일 안에 create 쿼리를 작성하고 Flyway가 적용된 스프링 부트 애플리케이션을 실행시키면

자동으로 Flyway가 Crew 테이블이 만들어지고 Flyway가 처음 적용되었기 때문에 자동적으로 데이터베이스 변경 이력이 저장되는 flyway_schma_history라는 테이블이 만들어진다.


[파일 이름 예시]


이 때 파일의 버전은 새로 적용하려는 파일은 기존에 적용된 파일의 버전보다 무조건 높아야 한다.

예를 들어 이미 V4까지 파일이 적용된 상태에서 V1과 V2 사이에 새로운 작업을 추가하고 싶다고 V1.2라는 새로운 마이그레이션 파일을 정의한다고 해도 무시되어 적용되지 않는다.


이미 Crew라는 테이블이 존재하는 DB에서 Flyway를 사용하여 Address라는 테이블을 생성하기 위해서는 어떻게 해야 할까??

우선 아무것도 입력하지 않은 V1__baseline.sql 파일을 만든 다음

그 다음 create address 쿼리 문이 적힌 V2__address.sql 파일을 작성하고 Flyway가 적용된 스프링 부트 애플리케이션을 실행시키면

Flyway가 자동적으로 Address 테이블을 만들고 처음 Flyway가 적용되었기 때문에 자동적으로 history 테이블도 생성된다.

Info는 Flyway가 처음으로 적용되면 자동으로 생성되는 flyway_schema_history 테이블에 저장되는데 이 중 중요한 것은 마이그레이션 파일의 버전이 기록되는 version 컬럼과 마이그레이션 파일의 해시값을 나타내는 checksum 컬럼이다.
version이 높아지면 파일이 적용되고 만약 기존에 적용된 파일에서 sql 쿼리가 변경된다면 Flyway는 파일이 오염되었다고 판단해 checksum 값을 바꿔버리고 이 변경된 checksum 값으로 인해 오류가 발생한다.
따라서 데이터베이스의 추가나 삭제같은 변경 작업을 진행하려면 항상 새로운 파일을 추가해서 진행해야 한다.
Spring Boot가 실행됨
flyway.enabled=true 설정으로 Flyway 활성화됨
classpath:db/migration 폴더에서 V1, V2 식으로 된 SQL 파일을 순서대로 찾음
이미 실행된 마이그레이션은 flyway_schema_history 테이블에 기록되어 있어, 다시 실행하지 않음
새로 추가된 SQL 파일만 실행함

MySQL 8.x 버전 이상부터는 build.gradle의 dependencies에
implementation 'org.flywaydb:flyway-mysql' // mysql 8.x 이상부터는 추가
까지 추가해줘야 한다.
spring:
flyway:
enabled: true # flway 실행(기본값 true)
url: jdbc:mysql://localhost:3306/${DB_NAME}?serverTimezone=Asia/Seoul # DB 주소
username: ${DB_USERNAME} # DB user 아이디
password: ${DB_PASSWORD} # DB user 비밀번
baseline-on-migrate: true # Baseline 적용(변경이력 테이블이 자동생성되지 않는 경우도 방지)
locations: classpath:db/migration #마이그레이션 파일 위치 지정(기본 위치: db/migration )
applicaion.yml에 해당 flyway 설정도 추가해줘야 한다.
[Flyway 기본 디렉토리 구조]
src
└── main
└── resources
└── db
└── migration
├── V1__create_users_table.sql
├── V2__create_questions_table.sql
└── V3__insert_sample_data.sql
디렉토리 구조는 자유롭게 커스텀이 가능하다.
[참고 문헌]
[10분 테코톡] 에단의 Flyway: https://www.youtube.com/watch?v=_fgOxPRo8tU
[10분 테코톡] 🐶 코기의 Flyway: https://www.youtube.com/watch?v=pxDlj5jA9z4&t=242s
우리 팀에서 Flyway를 사용하는 이유: https://ecsimsw.tistory.com/m/entry/Flyway%EB%A1%9C-DB-Migration
[Flyway] DB에 Flyway 적용하기: https://dbjh.tistory.com/90