[DB migration] Springboot & Flyway & MySQL

Kim Dae Hyun·2022년 2월 2일
1

JPA & hibernate 라는 유용한 툴을 너무 일찍 만난 탓인지 DB migration에 대해 잘 알지도, 알아야 할 일도 지금까지 딱히 없었다.

내가 이전에 마음대로 생각한 DB migration은 orale -> mysql ... mariaDB -> postgresql 이런 식으로 DB 자체를 변경하는 작업이었다. 뭐 이런 것도 일종의 migration 이겠지만 흔히 말하는 DB migration은 조금 다른 의미이다.

간단하게 이해해보면 DB migration 은 DB 스키마에 발생한 변경사항을 DB에 적용하는 것이다.
운영환경, 개발환경, 로컬환경 등 다양한 환경에서 각자의 DB를 갖고 있는데 이 모든 환경에서 DB의 스키마를 맞추기 위함인 것이다.

hibernate의 ddl-auto를 생각해보자.
update 혹은 create, create-drp 등을 사용했을 때 엔티티 클래스에 맞춰서 자동으로 클래스가 생성된다.
로컬환경에서는 크게 문제없이 ddl-auto 를 이용해서 스키마 (엔티티)의 변경사항을 자동으로 DB에 적용할 수 있었다. 하지만 이게 운영환경이라면 조금 위험한 부분이 있다.

일단 ddl-auto의 설정값을 변경하면 데이터가 모조리 지워지는 끔직한 상황이 생길 수 있다.
그리고 DB스키마 변경 작업은 애플리케이션에서 굉장히 중대한 사안에 해당할텐데 변경사항에 대한 추적관리가 되지 않는다면 문제가 발생했을 때 그 시작점을 찾기가 힘들 것이다.

따라서 ddl-auto로 스키마를 자동생성하는 방식 말고 따로 스키마 변경을 관리해줘야 한다.
Java 백엔드 진영에서는 Flyway 가 이 역할 수행한다.


📌 Flyway

FlywayDB migration tool 이다.
DB 스키마 변경에 대한 마이그레이션 작업과 변경에 대한 버전관리(형상관리)를 제공한다.

DB migration toolliquibase도 있는데 살짝 사용해 본 결과 Flyway가 조금 더 간단, 편리한 것 같다.

Springboot2.6.x 에서 Flyway 를 간단하게 사용해봤다.

Dependency

// pom.xml
<dependency>
	<groupId>org.flywaydb</groupId>
	<artifactId>flyway-core</artifactId>
</dependency>
// build.gradle
implementation group: 'org.flywaydb', name: 'flyway-core', version: '8.4.1'

application.properties

MySQL 8.0.x

ddl-auto를 통해 스키마가 생성되지 않도록 none 혹은 validate로 설정한다.

flyway에게 db username과 password를 제공한다.

spring.datasource.username=username
spring.datasource.password=password
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/bookdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.jpa.hibernate.ddl-auto=validate

spring.sql.init.mode=always

spring.flyway.user=username
spring.flyway.password=password

일단 이정도만 설정하면 마이그레이션과 스키마 변경 버전관리가 가능하다.

Entity 생성

MySQL의 모든 스키마를 지우고 테스트를 위한 간단한 Entity를 생성한다.

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String title;
    private String isbn;
    private String publisher;

    public Book() {
    }

    public Book(String title, String isbn, String publisher) {
        this.title = title;
        this.isbn = isbn;
        this.publisher = publisher;
    }
    
    // getter, setter, equals, hashCode 생략 ...
}    

이전에는 ddl-auto를 이용해서 위 Entity에 해당하는 스키마를 생성했겠지만 이번에는 flyway를 이용한다.

V1 DDL 작성

flyway는 스키마 변경에 대한 버전관리를 도와준다.
버전에 대한 정보는 개발자가 직접 작성한다.

스키마 생성을 위한 DDL 작성 전에 flyway 를 사용하려면 기본적으로 두 가지 규칙을 지켜야 한다.

  1. DDL 파일 경로
    아무런 설정이 없다면 resources.db.migration 이 기본 경로이다.
    경로를 변경하고 싶다면 spring.flyway.locations=classpath:/db/migration을 변경하자.

  2. 네이밍 규칙
    V버전__설명.sql
    위 규칙을 지켜서 sql 파일을 작성해야 한다.
    V 외 다른 기능을 수행하는 prefix도 있지만 일단 V 부터 알아보자.

[ resources.db.migration.V1__init_db ]

drop table if exists book;
drop table if exists hibernate_sequence;

create table book (
      id bigint not null,
      isbn varchar(255),
      publisher varchar(255),
      title varchar(255),
      primary key (id)
) engine=InnoDB;

create table hibernate_sequence (
    next_val bigint
) engine=InnoDB;

insert into hibernate_sequence values (1);


테이블을 모두 drop 하고 애플리케이션을 실행한다.

실행결과 의도한 대로 book 스키마가 생성되었고 스키마 변경에 대한 버전관리를 해줄 flyway_schema_hisory도 생성되었다.

테이블 추가

테이블을 하나 더 추가해야 하는 스키마 변경사항이 발생했다면 동일하게 DDL 을 작성하고 Flayway를 통해 마이그레이션 작업을 수행해야 한다.

Authro 테이블을 추가해야 한다.
Entity 는 아래와 같다.

@Entity
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    public Author() {
    }

    public Author(String name) {
        this.name = name;
    }
    
    // getter, setter, equals, hashCode 생략 ...
 }   

이제 위 엔티티에 해당하는 DDL을 작성한다.
파일명은 앞선 V1__init_db.sql보다 버전이 높은 V2__add_author.sql로 한다.

[ resources.db.migration.V2__add_author.sql ]

create table author (
        id bigint not null,
        name varchar(255),
        primary key (id)
) engine = InnoDB;

의도한 대로 Author 테이블이 추가되었다.

++ Flyway는 굉장히 잘 되어있는 문서를 제공한다. 문서만 잘 읽어봐도 바로 프로젝트에 적용해볼 수 있을 것 같다. very 땡큐~


📌 참고

Flyway Documentation

profile
좀 더 천천히 까먹기 위해 기록합니다. 🧐

0개의 댓글