[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 Framework/Spring boot2] - [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)
'Spring Framework > Spring boot #2' 카테고리의 다른 글
[Spring Boot #30] 스프링 부트 시큐리티 커스터마이징 (0) | 2021.03.25 |
---|---|
[Spring Boot #29] 스프링 부트 시큐리티 (0) | 2021.03.25 |
[Spring Boot #28] 스프링 부트 몽고DB(Mongo DB) 연동하기 (0) | 2021.03.25 |
[Spring Boot #27] 스프링 부트 레디스(Redis) 연동하기 (0) | 2021.03.25 |
[Spring Boot #25] 스프링 부트 데이터베이스 초기화 (0) | 2021.03.25 |
[Spring Boot #24] 스프링 부트 Spring-Data-JPA 연동 (0) | 2021.03.25 |
[Spring Boot #23] 스프링 부트 PostgreSQL 연동하기 (0) | 2021.03.25 |
[Spring Boot #22] 스프링 부트 DBCP 및 MySQL 연동해보기 (0) | 2021.03.25 |