웹 애플리케이션 프로젝트에서 DB 마이그레이션을 위해 사용했던 Flyway에 대해 정리해보겠다.
Flyway
Flyway는 오픈소스 DB 마이그레이션 툴이다. 핵심적으로 무엇을 도와주냐면, DB 스키마에 대한 변경을 추적하고 업데이트나 롤백을 쉽게 진행하도록 애플리케이션의 DB 스키마 버전 관리를 도와준다. 자바/스프링 프로젝트를 위한 툴이 아닌 다른 언어로 된 애플리케이션을 사용할 때도 쓸 수 있고, CLI나 API 등을 지원하기도 하고 데스크탑 애플리케이션도 존재한다.
왜 변경사항을 추적할까?
로컬 디바이스, 우리의 컴퓨터에서 개발을 할 때는 변경의 추적이 상관없을 수도 있다. 내가 개발해서 내가 사용한다면 그 안의 데이터를 내가 직접 관리하고, 그 관리가 중요하지 않을 수도 있지 않은가? 하지만 변경의 추적이 필요한 환경들이 존재한다.
로컬 환경에서 개발하다가 공통적으로 사용될 개발 서버의 DB, 혹은 실제로 릴리즈가 될 프로덕션 서버의 DB에서 만약 변경이 필요하다고 가정해보자. 스키마를 추가하거나 변경 시 DB에 접속해 하드하게 수정할 수 있다. 그렇게 되면 이미 존재하는 데이터에 이상이 생길 수도 있다. 제약이 무너질 수도 있고 의도하지 않은 데이터의 추가나 손실이 발생할 수 있다. 무슨 깡으로 공통 환경의 DB를 건들 수 있을까! 스크립트를 매번 직접 실행하는 것은 번거롭고 실수할 확률이 상당하다.
JPA를 사용하면 ddl-auto: create-drop
이라는 옵션을 통해 서버가 재실행 될 때마다 ddl을 JPA 엔티티에 따라 스키마를 초기화 후 재생성을 할 수 있다. 프로덕션 서버의 스키마를 초기화 하는 것은 더더욱 말이 안된다! ddl-auto: update
를 사용하면? 문제없을 수도 있겠지만, 만약 엔티티 정의할 때 실수했다면 어떻게 돌릴 것인가?
안정적인 운영을 위해 DB의 버전 관리는 매우 탁월한 선택이다.
사용 방법
Flyway는 애플리케이션이 시작할 때 CLI나 API로 작동시킬 수도 있고, 혹은 데스크탑 애플리케이션을 통해서 작업할 수도 있다. 감사하게도, 스프링부트 프로젝트를 진행할 때엔 라이브러리가 존재한다. 파이썬 프레임워크를 사용할 때엔 SQLAlchemy나 Pyway 등으로 대신할 수도 있다.
스프링부트 프로젝트에 Flyway 의존성을 추가해 사용하는 방법을 본격적으로 포스팅해보려 한다!
Flyway 의존성 추가
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql' // MySQL 8.0 이상 버전을 사용할 때 필요한 의존성
Maven Repository에서 검색해 flyway를 버전 별로 추가할 수 있다. MySQL 버전이 8.0 이상이라면 flyway-mysql
의존성이 필수다!
application.yaml
설정 추가
spring:
flyway:
enabled: true // 기본
기본 설정이 enabled: true
다. Flyway 의존성이 추가된 상황이라면 기본적으로 Flyway가 실행된다. 만약 테스트 시 H2 같은 인메모리 DB를 사용하거나 ddl-auto: create-drop
등의 설정을 사용한다면 enabled: false
로 테스트 시 실행을 피할 수 있다!
스키마 추가
기본적으로 스키마를 추가하기 위해 읽는 경로는 {project}/src/main/resources/db/migration
이다. 해당 디렉토리 아래에 명명 규칙을 지킨 SQL 스크립트를 넣어주면 그에 맞게 동작한다. 테스트 시에도 Flyway를 사용해도 해당 경로에서 읽는다.
SQL 스크립트 파일 명명 규칙
명명 규칙은 위와 같다!
- V + 숫자: 정수인 숫자가 작은 버전부터 마이그레이션을 실행하거나 변경을 확인한다.
- U + 숫자: Undo. 즉, 버전 숫자에 해당하는 마이그레이션 스크립트까지 롤백한다. 예를 들어, V10까지 마이그레이션이 존재하고 U6가 있다면 V5가 될 때까지 마이그레이션을 롤백한다. 만약 해당 숫자의 마이그레이션 스크립트가 없다면 아무것도 하지 않는다. Undo를 사용할 땐 조심해야한다. 만약 V10까지 마이그레이션이 존재하고 중간에 실패한 마이그레이션이 있더라도 어쨌든 되돌리기 때문이다. 아직은 쓸 일은 없을 것 같다. 왜냐하면 유료다!
- R: Repeat. 마이그레이션이 전부 진행되거나 확인된 후 매번 애플리케이션 실행 시 실행되는 스크립트다.
마이그레이션 스크립트 추가
위에 언급했던 경로 아래에 V1
스크립트를 추가한다. 버전 뒤에는 기본적으로 언더스코어가 두개여야한다. 예를 들면, V1__initial_schema.sql
과 같이 말이다.
V1__initial_schema.sql
CREATE TABLE users
(
id BIGINT AUTO_INCREMENT,
nickname VARCHAR(20) UNIQUE,
created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
CONSTRAINT users_pk PRIMARY KEY (id)
);
CREATE TABLE posts
(
id BIGINT AUTO_INCREMENT,
user_id BIGINT NOT NULL,
title VARCHAR(30) NOT NULL,
content TEXT,
thumbnail_url VARCHAR(1024),
created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
CONSTRAINT posts_pk PRIMARY KEY (id)
);
간단하게 유저와 포스트 테이블을 만들었다.
물론, separator인 2개의 언더스코어나 버전을 명시하는 V
는 기본으로 설정되어 있기 때문에 application.yaml
에서 변경할 수 있다.
spring:
flyway:
sql-migration-prefix: VERSION
sql-migration-separator: --
굳이 기본 설정을 바꿀 필요는 못 느낀다.
스키마 추가/변경 시 새로운 버전의 추가 스키마 작성
스키마 경로인 /db/migration
아래에 V2__변경내용.sql
을 추가해준다.
V2__create_post_like_table.sql
ALTER TABLE posts ADD COLUMN like_count INTEGER NOT NULL DEFAULT 0;
CREATE TABLE post_likes
(
user_id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
is_like TINYINT(1) NOT NULL,
created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
CONSTRAINT post_likes_pk PRIMARY KEY (user_id, post_id),
CONSTRAINT post_likes_users_fk FOREIGN KEY (user_id) REFERENCES users (id),
CONSTRAINT post_likes_posts_fk FOREIGN KEY (post_id) REFERENCES posts (id)
);
좋아요 테이블을 추가하고 반정규화로 포스트 별 좋아요 수를 조회하기 위해 포스트 테이블에 좋아요 수 속성을 추가했다.
어떻게 버전 관리를 할 수 있을까?
Flyway는 자동으로 하나의 테이블을 추가 생성한다.
기본적으로 flyway_schema_history
라는 테이블을 자동으로 생성해준다. 해당 테이블을 통해 Flyway는 버전 관리를 한다. 해당 테이블의 튜플들을 보면,
이와 같다. 실행 순서, 버전, 설명 등이 자동으로 채워지고, 체크섬을 확인할 수 있다. 현재 DB와 체크섬을 비교해 현재 DB의 버전을 알 수 있고, 다음 버전이 적용가능한지 유효성을 판단한다. 성공여부와 마이그레이션이 진행된 날짜까지 나오니 기록으로 쓰기에도 너무 좋다!
더미 데이터를 추가하고 싶다면?
스키마를 정의하는 것은 이처럼 간단하게 진행했다. 추가나 변경이 있을 시 버전 관리를 통해 효과적으로 DB를 관리할 수 있다. 프로덕션 DB에서는 용이하게 사용가능한 것이 확실한데, 로컬 DB에서도 Flyway를 똑같이 사용해서 실제 프로덕션 환경에서의 동작을 보장할 필요가 있다. 그렇다면 로컬 DB에서 더미 데이터를 추가하고 싶을 땐 어떡할까? 실제 프로덕션 환경에선 더미 데이터가 추가되지 말아야하고, 로컬 DB에선 더미 데이터를 관리할 필요가 있다면 어떻게 해야할까. 다음 포스트에선 그 경험에 대해 작성해보고자 한다!
References
'Spring > 라이브러리' 카테고리의 다른 글
Flyway를 이용한 로컬 환경 더미 데이터 생성 (0) | 2024.04.06 |
---|