[27] Spring Data : Database Migration Tool (FlyWay)
FlyWay는 DB schema 또는 data 변경에 대한 SQL script file을 version control처럼 관리할 수 있는 Database Migration Tool 중 하나입니다.
예제는 이전 포스팅에서 작성한 것을 이어서 사용하시면 됩니다.
pom.xml file에 FlyWay를 사용하기 위한 의존성을 추가해 줍니다.
...
<dependencies>
...
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
...
</dependencies>
...
이전 예제 실행 때 생성된 relation을 모두 삭제해 주세요. (docker container를 삭제 후 새롭게 생성하여 실행하거나 drop table 해주시면 됩니다.)
(참고) docker는 container가 사라지면 data도 같이 없어집니다. 따라서 localhost의 특정 directory(volume)와 mapping 시켜놓고 container가 사라져도 data를 유지하도록 할 수 있습니다.
resources directory 밑에 sql script file의 version 관리를 위한 db/migration/ directory를 추가합니다.으로 추가하도록 하겠습니다. 만약 여러 db vendor에 대해 관리해야 한다면 db/migration/postgres, db/migration/mssql 등과 같이 각 vendor마다 directory를 만들어 관리할 수 있습니다. 이후 version 관리를 위한 file name format에 맞춰 SQL script file을 쌓아가면 됩니다.
application.properties file의 spring.flyway.locations property에 사용자가 원하는 sciprt file location을 지정할 수도 있습니다.
version 관리를 위한 file name format의 예
V1__init.sql
- 처음 문자는 대문자 V로 시작합니다.
- 대문자V 후에는 숫자를 입력합니다.
- under bar 두 개를 입력합니다.
- 이 file의 작업을 간략하게 표현하여 입력합니다.
위에서 생성한 /resrouces/db/migration directory에 V1__init.sql file을 생성하고 그 내용을 다음과 같이 넣어줍니다.
drop table if exists users;
drop sequence if exists hibernate_sequence;
create sequence hibernate_sequence start with 1 increment by 1;
create table users (id bigint not null, email varchar(255), note varchar(255), password varchar(255), username varchar(255), primary key (id));
version관리용 SQL script file에서는 문법을 정확히 지켜야 하며 각 구문은 모두 semicolon(;)으로 끝날 수 있도록 합니다.
FlyWay로 생성되는 schema를 hibernate에서 확인하기 위해 application.properties file에서 spring.jpa.hibernate.ddl-auto가 validate로 설정되어 있는지 확인합니다. 안되어 있다면 validate로 바꿔주세요.
이제 application을 실행하면 다음의 순서대로 실행 될 것을 기대할 수 있습니다.
- ApplicationContext 실행
- FlyWay 실행 - version controlled SQL script file을 통한 DB schema 생성
- Hibernate - schema의 validation check를 진행.
schema를 확인해보면 생성한 users table외에 flyway_schema_history table이 생성되어 있는 것을 확인할 수 있습니다.
이 table은 SQL 관리 내역이 쌓는데 사용합니다.
이 상태에서 새로운 column을 추가해보도록 합니다. Users class에 활성화된 유저인지 확인하기 위한 isActivated field와 해당하는 getter/setter를 추가합니다. 수정된 code는 다음과 같습니다.
@Entity
public class Users {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
private String note;
private String email;
private boolean activated;
public boolean isActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
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;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Users users = (Users) o;
return Objects.equals(id, users.id) &&
Objects.equals(username, users.username) &&
Objects.equals(password, users.password);
}
@Override
public int hashCode() {
return Objects.hash(id, username, password);
}
}
이대로 실행하면 FlyWay에서는 특별히 진행한 작업이 없으므로 V1__init.sql의 내용대로만 table을 생성하고 hibernate에서 validation을 진행 중에 mapping 불가능한 field가 있기 때문에 error를 발생하게 됩니다.
이제 새로운 column 추가를 위한 SQL script file을 생성합니다. file명은 V2__add activated.sql로 했습니다.
file 내용은 다음과 같이 작성합니다.
ALTER TABLE users ADD COLUMN activated BOOLEAN;
(주의) 기존의 SQL script file은 절대 수정하면 안 됩니다. 어떤 내용의 작업을 진행했는지 FlyWay에서 관리 중이기 때문입니다. schema 변동 시 새로운 SQL script를 작성하여 처리해야 version 관리가 되는 것에 유의해 주세요.
application을 실행하면 의도한대로 schema의 변경됩니다.