들어가면서
안녕하세요. 요즘에 플러피(fluffy)라는 온라인 시험 문제 제작 및 관리 서비스를 만들고 있습니다.
플러피에서는 시험 문제를 만들 때 지시문과 선택지만을 작성할 수 있었습니다.
문제를 표현하기에 한계가 있어 지문을 추가해달라는 피드백이 있었습니다.
현재 서비스는 배포 중인 상태이고 데이터가 이미 존재하기 때문에 데이터베이스 스키마를 모두 지우고 새로 생성하는 방법은 사용할 수 없습니다. 간단하게 떠올린 방법은 데이터베이스에 직접 들어간 후 질문 테이블에 지문 컬럼을 추가하는 방법이 있습니다. 다음과 같이 SQL 문을 실행하면 됩니다.
ALTER TABLE 질문 ADD COLUMN 지문 TEXT NOT NULL DEFAULT '';
하지만 이 방법은 데이터베이스에 직접 접근해 수정하기 때문에 다음과 같은 문제가 발생할 수 있습니다.
- 일관성: 데이터베이스의 상태가 애플리케이션의 코드와 일치하지 않게 될 수 있습니다. 이는 데이터 무결성을 해칠 수 있습니다.
- 버전 관리 부족: 어떤 변경이 언제 이루어졌는지 기록이 남지 않기 때문에 추적이 어렵습니다. 특히 여러 개발자가 동시에 작업하는 경우 혼란을 초래할 수 있습니다.
이러한 문제를 해결하기 위해 데이터베이스 마이그레이션 도구인 Flyway를 사용하려고 합니다.
Flyway란?
Flyway는 오픈 소스 데이터베이스 마이그레이션 도구로, 데이터베이스 스키마의 버전 관리를 체계적으로 수행할 수 있도록 도와줍니다.
테이블에 새로운 컬럼을 추가하거나 기존 컬럼을 삭제하는 등 데이터베이스의 구조가 변경될 때, Flyway는 이러한 변경 사항을 효과적으로 관리하고 추적하는 데 유용합니다. Flyway는 SQL 스크립트를 사용하여 데이터베이스의 상태를 정의하며, 이를 통해 데이터베이스의 버전을 효율적으로 관리할 수 있습니다.
Flyway 사용하기
Spring, JPA, MySQL을 사용하는 프로젝트에서 Flyway를 사용하는 방법을 알아보겠습니다.
이미 Entity는 작성되어 있다고 가정하고 진행하겠습니다.
Flyway를 사용하기 위해 프로젝트에 의존성을 추가해야 합니다. Gradle을 사용하는 경우 다음과 같이 의존성을 추가할 수 있습니다.
예시에서는 MySQL 데이터베이스를 사용하므로 MySQL JDBC 드라이버와 Flyway의 MySQL 모듈을 추가했습니다.
dependencies {
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
}
로컬에서 개발하는 경우
로컬에서 개발하는 경우 실제 데이터베이스를 사용하기보다는 H2와 같은 인메모리 데이터베이스를 사용합니다.
이 경우 Flyway를 사용하지 않기 위해서 다음과 같은 설정이 필요합니다. 참고로, spring.flyway.enabled의 기본값은 true입니다.
# application-local.yml
spring:
flyway:
enabled: false
jpa:
hibernate:
ddl-auto: create-drop
처음 사용하는 경우
아직 운영하는 데이터베이스가 없고, 처음부터 데이터베이스를 구성해야 하는 경우 Flyway를 사용하여 데이터베이스 스키마를 생성할 수 있습니다. spring.jpa.hibernate.ddl-auto 속성을 validate로 설정하면 애플리케이션을 시작할 때 데이터베이스 스키마를 검증하고, 다를 경우 오류를 발생시킵니다.
# application-prod.yml
spring:
flyway:
enabled: true
jpa:
hibernate:
ddl-auto: validate
우선 첫 번째 마이그레이션 스크립트를 작성해야합니다. Flyway는 마이그레이션 스크립트를 버전 순서대로 실행하며, 마이그레이션 스크립트의 파일명은 V{버전 번호}__{스크립트 이름}.sql
와 같은 형식을 따라야 합니다.
스크립트 파일의 위치는 기본적으로 src/main/resources/db/migration
에 있어야 하고, 이 위치는 spring.flyway.locations
속성을 통해 변경할 수 있습니다.
첫 번재로 실행할 마이그레이션 스크립트의 파일명은 V1__init.sql
과 같이 작성합니다.
이미 작성되어 있는 Entity를 기반으로 테이블을 생성하는 스크립트를 작성합니다.
-- V1__init.sql
CREATE TABLE question (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title TEXT NOT NULL,
);
이제 애플리케이션을 실행하면 Flyway가 자동으로 마이그레이션 스크립트를 실행하고 데이터베이스 스키마를 생성합니다.
Flyway는 데이터베이스에서 flyway_schema_history 테이블을 생성하고, 실행한 마이그레이션 스크립트의 정보를 저장합니다.
데이터베이스에 접속해 flyway_schema_history 테이블을 확인하면 작성했던 마이그레이션 스크립트의 정보를 확인할 수 있습니다.
참고로, checksum을 통해서 마이그레이션 스크립트의 내용이 변경되었는지를 확인하기 때문에 이미 작성된 마이그레이션 스크립트를 수정하면 오류가 발생할 수 있습니다.
다음으로, 지문 컬럼을 추가하는 마이그레이션 스크립트를 작성합니다. Entity를 수정하는 부분은 생략하겠습니다.
-- V2__add_question_content.sql
ALTER TABLE question ADD COLUMN content TEXT NOT NULL DEFAULT '';
이제 애플리케이션을 실행하면 Flyway가 자동으로 마이그레이션 스크립트를 실행하고 데이터베이스 스키마를 변경합니다.
데이터베이스에 접속해 flyway_schema_history 테이블을 확인하면 작성했던 새로운 버전의 마이그레이션 스크립트의 정보를 확인할 수 있습니다.
데이터베이스에 이미 스키마가 존재하는 경우
플러피 서비스는 이미 데이터베이스에 스키마가 존재하는 상태입니다. 대부분의 프로젝트가 초기 단계에서 Flyway를 사용하지 않기 때문에 이러한 경우가 많습니다. 이러한 경우를 가정해서 Flyway를 사용하는 방법을 알아보겠습니다.
우선 Question Entity에 title, content 필드가 있고, 데이터베이스에도 question 테이블에 title, content 컬럼이 존재한다고 가정하겠습니다. 그 후, Entity에 category 필드를 추가하고, 다음과 같이 마이그레이션 스크립트를 작성합니다.
-- V2__add_question_category.sql
ALTER TABLE question ADD COLUMN category VARCHAR(255) NOT NULL DEFAULT '';
기존에 있던 스키마를 기반으로 마이그레이션 스크립트를 작성하기 위해서 Flyway의 baseline-on-migrate 속성을 true로 설정합니다.
baseline-version 속성을 통해 기존 스키마의 버전을 설정할 수 있습니다. 기본값은 1입니다.
기존 버전이 1이기 때문에 위에서 작성한 마이그레이션 스크립트 파일의 이름을 V2__add_question_category.sql
로 작성했습니다.
# application-prod.yml
spring:
flyway:
enabled: true
baseline-on-migrate: true
baseline-version: 1 # 기존 스키마의 버전 default=1
jpa:
hibernate:
ddl-auto: validate
이제 애플리케이션을 실행하면 flyway_schema_history이 생성되고, Flyway BaseLine 행이 쌓이 후에 마이그레이션 스크립트가 실행됩니다. 데이터베이스에 접속해 flyway_schema_history 테이블을 확인하면 작성했던 마이그레이션 스크립트의 정보를 확인할 수 있습니다.
참고로, baseline-version을 1로 설정했기 때문에 V1__init.sql 파일은 실행되지 않습니다.
그래도 현재 스키마 상태를 알 수 있도록 V1__init.sql 파일을 작성해두는 것이 좋습니다.
마치며
이번 글에서는 Flyway를 사용하여 데이터베이스 스키마를 관리하는 방법을 알아보았습니다.
Flyway는 데이터베이스 스키마의 버전 관리를 위한 간단하고 효과적인 도구이지만 한계가 있습니다.
스냅샷이나 Undo 기능이 유료 버전에서만 제공되기 때문에 이러한 기능이 필요한 경우 비용을 지불해야 합니다.
또한, Flyway는 기본적으로 단순한 마이그레이션에 적합하기 때문에 복잡한 마이그레이션이 필요한 경우 Liquibase를 사용하는 것이 더 적합할 수 있습니다.
이 글이 Flyway를 사용하여 데이터베이스 스키마를 관리하는 데 도움이 되었기를 바랍니다. 감사합니다.
현재 개발 중인 온라인 시험 문제 제작 및 관리 서비스 플러피에도 많은 관심 부탁드립니다.
'웹 백엔드' 카테고리의 다른 글
무중단 배포(블루/그린 배포)로 서비스 중단 없이 배포하기 (0) | 2025.01.09 |
---|---|
Git Submodule(서브모듈)을 통해서 Spring 설정(yml) 관리하기 (0) | 2025.01.05 |
@JsonTypeInfo와 @JsonSubTypes를 활용하여 요청 데이터에 다형성을 적용해 보자 (1) | 2024.12.25 |
Spring JPA를 사용할 때, OneToMany에서 Fetch Join 사용 시 문제점을 알아보자 (0) | 2024.12.23 |
Spring JPA를 사용할 때 findByXxxId의 문제점을 알아보자 (0) | 2024.12.23 |