[Spring Boot #26] Flyway를 이용한 데이터 마이그레이션

| Flyway란?

  • Flyway는 오픈소스 마이그레이션 툴입니다. 
  • 자바나 c++같은 프로그램의 소스 코드는 svn, git과 같은 형상관리 툴로 쉽게 관리할 수 있지만 테이블의 스키마나 데이터는 위와 같은 툴로 변경이력을 관리할 수 없습니다. 따라서 SQL 스크립트문을 실행하거나 직접 DB 콘솔이나 Toad 같은 툴을 통해 직접 수동으로 처리해줘야 하는 단점이 있습니다.
  • Flyway는 버전 관리 목적인 SCHEMA_VERSION 테이블을 통해 SQL 스크립트의 변화를 추적하면서 자동적으로 관리하는 방법으로 위와 같은 문제를 해결합니다.

| 스프링 부트에서 Flyway 사용하기


의존성 추가

<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>


프로젝트 구조

├── pom.xml
├── spring-boot-tutorial.iml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │   └── tutorial
│   │   │   └── springboottutorial
│   │   │   ├── Account.java
│   │   │   ├── AccountRepository.java
│   │   │   └── SpringBootTutorialApplication.java
│   │   └── resources
│   │   ├── application.properties
│   │   ├── db │   │   │   └── migration │   │   │   ├── V1__init.sql │   │   └── templates

  • resource 디렉터리에 db.migration 디렉터리를 추가해서 V1__init.sql 파일을 만듭니다. 이 파일은 Flyaway가 관리하는 SCHEMA_VERSION역할을 하는 테이블이 됩니다. 
  • 위 SCHEMA_VERSION의 역할을 하는 테이블은 꼭 따라야하는 네이밍 컨벤션이 있습니다. 그에 관련된 내용은 여기 링크에서 확인하시면 더 자세히 나와있습니다. 


V1__init.sql

--V1_init.sql
drop table account if exists;
drop sequence if exists hibernate_sequence;
create sequence hibernate_sequence start with 1 increment by 1;
create table account (id bigint not null, email varchar(255), password varchar(255), username varchar(255), primary key (id));
  • 파일에 작성되어 있는 SQL문을 가지고 버전관리를 하게 됩니다.


application.properties

# application.properties
spring.datasource.hikari.maximum-pool-size=4

spring.datasource.url=jdbc:postgresql://localhost:5432/springboot
spring.datasource.username=saelobi
spring.datasource.password=pass

# 드라이버가 createClub을 지원하지 않아서 warning 뜨는 것을 방지
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true


소스 코드

@Entity
public class Account {

@Id
@GeneratedValue
private Long id;

private String username;

private String password;

private String email;

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Account account = (Account) o;
return Objects.equals(id, account.id) &&
Objects.equals(username, account.username) &&
Objects.equals(password, account.password);
}

@Override
public int hashCode() {
return Objects.hash(id, username, password);
}
}
public interface AccountRepository extends JpaRepository<Account, Long> {

Optional<Account> findByUsername(String username);
}
@SpringBootApplication
public class SpringBootTutorialApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootTutorialApplication.class, args);
}
}


다음 postgres DB를 docker를 통해 구동합니다. 구동 방법은 아래 포스팅을 참조하시면 됩니다.


[Spring/Spring Boot] - [Spring Boot #23] 스프링 부트 PostgreSQL 연동하기


위 프로젝트를 실행하게 되면 Flyway 어플리케이션이 실행되면서 V1__init.sql에 있는 SQL문을 실행한 뒤 postgres DB에 스키마를 생성하게 됩니다. 따라서 엔티티와 테이블간의 매핑이 이루어져 Spring-Data-JPA에 의한 유효성 검사도 자연스럽게 통과가 됩니다.


List of relations
Schema | Name | Type | Owner
--------+-----------------------+-------+---------
public | account | table | saelobi
public | flyway_schema_history | table | saelobi
(2 rows)

flyway_schema_history는 Flyway가 SCHEMA_VERSION 테이블을 실행했을 시 관련 히스토리 정보를 관리하는 테이블입니다.

springboot=# select * from flyway_schema_history;
installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success
----------------+---------+-------------+------+--------------+------------+--------------+----------------------------+----------------+---------
1 | 1 | init | SQL | V1__init.sql | 1467134063 | saelobi | 2019-01-11 01:42:22.067858 | 25 | t
(1 row)


| Flyway를 사용하여 스키마 변경이력 관리하기


이제 엔티티 역할을 하는 Account 클래스에 변수를 하나 추가합니다.

@Entity
public class Account {

@Id
@GeneratedValue
private Long id;

private String username;

private String password;

private String email;

private boolean active;

public String getEmail() {
return email;
}

public boolean isActive() {
return active;
}

public void setActive(boolean active) {
this.active = active;
}

public void setEmail(String email) {
this.email = email;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Account account = (Account) o;
return Objects.equals(id, account.id) &&
Objects.equals(username, account.username) &&
Objects.equals(password, account.password);
}

@Override
public int hashCode() {
return Objects.hash(id, username, password);
}
}

만일 이 상태로 어플리케이션을 실행했을 경우 DB에 있는 account 테이블과 매핑이 되지 않기 때문에 유효성 검사에서 에러를 내게 되어 어플리케이션이 제대로 구동되지 않을 것입니다.


따라서 이러한 변경사항을 반영할 수 있도록 Flyway의 SCHEMA_VERSION sql 파일을 하나 추가해야합니다. 한 번 적용이 된 V1__init.sql 파일은 절대로 변경해서는 안됩니다.

│   │       ├── db
│   │   │   └── migration
│   │   │   ├── V1__init.sql
│   │   │   └── V2__add_active.sql


V2_add_active.sql

ALTER TABLE account ADD COLUMN active BOOLEAN;


어플리케이션을 실행하면 다음과 같이 DB에 정상적으로 SQL문이 반영된 것을 알 수 있습니다.

springboot=# select * from account;
id | email | password | username | active
----+-------+----------+----------+--------
(0 rows)

springboot=# select * from flyway_schema_history;
installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success
----------------+---------+-------------+------+--------------------+------------+--------------+----------------------------+----------------+---------
1 | 1 | init | SQL | V1__init.sql | 1467134063 | saelobi | 2019-01-11 01:42:22.067858 | 25 | t
2 | 2 | add active | SQL | V2__add_active.sql | 1099198921 | saelobi | 2019-01-11 01:58:32.238285 | 4 | t
(2 rows)


참고자료 : https://www.inflearn.com/course/스프링부트


이 글을 공유하기

댓글(0)

Designed by JB FACTORY