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는 DB migration tool
이다.
DB 스키마 변경에 대한 마이그레이션 작업과 변경에 대한 버전관리(형상관리)를 제공한다.
DB migration tool
로 liquibase도 있는데 살짝 사용해 본 결과 Flyway가 조금 더 간단, 편리한 것 같다.
Springboot2.6.x 에서 Flyway 를 간단하게 사용해봤다.
// 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'
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
일단 이정도만 설정하면 마이그레이션과 스키마 변경 버전관리가 가능하다.
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를 이용한다.
flyway는 스키마 변경에 대한 버전관리를 도와준다.
버전에 대한 정보는 개발자가 직접 작성한다.
스키마 생성을 위한 DDL 작성 전에 flyway 를 사용하려면 기본적으로 두 가지 규칙을 지켜야 한다.
DDL 파일 경로
아무런 설정이 없다면 resources.db.migration
이 기본 경로이다.
경로를 변경하고 싶다면 spring.flyway.locations=classpath:/db/migration
을 변경하자.
네이밍 규칙
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 땡큐~