Flyway
Flyway는 DB의 형상관리를 목적으로 하는 툴이다.
1. DB Migration 필요한 것일까?
현재 우리는 배포 후 데이터를 관리해본 경험이 없다.
유지 보수 중 스키마 구조가 바뀌는 상황에 어떻게 대처할 것인가?
예제로 알아보자
현재 유지보수 중인 테이블 (SampleEntity)이 다음과 같다고 가정하자!
@Entity
public class SampleEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
헌데, 새로운 요구사항이 추가되었다. age 필드를 추가해야한다.
그렇다면, Entity에서는 단순히 private Integer age를 추가하면 된다.
@Entity
public class SampleEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
}
하지만 실제 DB의 상황에서 변화를 어떻게 처리할 것인가?
방법1. DB 서버에 들어가 테이블 직접수정한다
해당 DB에 접속하여 다음의 스키마를 입력해준다. 하지만 단점이있다.
ALTER TABLE sample_entity ADD COLUMN age integer default 0
- 실수하기 좋다
- 작업하기 번거롭다
- 만약 데이터가 미리 있고, Entity쪽만 변경(age추가), DB 스키마를 수정하지 않았다면? 아래와 같은 에러가 발생할 것이다.
Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'age' in 'field list'
방법2. Flyway 툴을 사용하자
궁극적인 목표
- DB에 접속해서 TABLE을 직접 건들지 않으며, age 컬럼 포함한 신규데이터를 저장한다.
- 이전 나이가 포함되지 않는 데이터는 나이 필드를 0으로 초기화한다.
- git으로 관리한다 → 파일로 관리할 수 있어야 한다.
Flyway를 사용해보자
1. 의존성 추가 build.gradle
dependencies {
implementation('org.flywaydb:flyway-core:6.4.2')
}
2. 어플리케이션 설정 추가 : application.yml
- data source 설정 (DB정보)
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:tcp://localhost/~/flyway
username: sa
password:
- flyway 설정
spring:
jpa:
generate-ddl: false
flyway:
enabled: true
- Spring boot 2 이상의 경우 아래 설정 추가
spring:
flyway:
baseline-on-migrate: true
3. init 파일 추가: resources/db/migration/
등록하려는 시점의 DB 스키마 구조를 입력해야 한다.
이 파일을 기준으로 flyway가 DB버전 관리를 하게된다.
- 버전 관리가 어렵다면 일단 V {숫자}__{설명}. sql 으로 생각하자. (더 자세한 내용은 아래내용을 참조하자)
V1__init.sql :등록시점의 DB 스키마 구조 입력
drop table if exists sample_entity;
create table sample_entity(
id bigint auto_increment,
name varchar(255),
primary key (id)
);
엔티티 변경 적용
1. 컬럼 추가 (변경 전 ddl-auto: validate로 설정한다)
public class SampleEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age; // 추가한 부분
}
2. V2__add_age.sql
ALTER TABLE sample_entity ADD COLUMN age integer default 0
프로덕션 코드 실행
프로덕션 코드를 실행하면 flyway_schema_history 테이블이 생성된다.
버전관리는 어떻게 하는가?
Prefix
- V(Versioned): 현재버전을 새로운 버전으로 업데이트
- U(Undo): 현재 버전을 이전버전으로 되돌리는 경우
- R(Repeatable): 버전에 관계 없이 매번 실행하는 경우
Version
스크립트의 버전을 이전보다 꼭 높게 적어야 한다.
- V와 U는 버전을 명시한다.
- R은 버전을 명시하지 않는다. (매번 실행되기 때문이다)
Separator
무조건 __(언더바 2개)로 작성
Description
스크립트 내용에 맞게 자유롭게 적는다.
단어 구분은 _(언더바 1개)로 한다.
트러블슈팅
테스트 환경에서의 Flyway 실패
1. h2 테스트 환경
- h2에서 jdbc:h2:mem:testdb;MODE=MYSQL 을 적용
- V1__init.sql의 engine=InnoDB default charset utf8mb4; 부분에서 에러가 발생함
해결방법
- h2 문법으로 적용하면 성공이 됨 → 스키마를 h2, MySQL 둘다 관리해야 하기 때문에 적용X
- 로컬 test DB를 MySQL로 변경
2. MySQL 테스트 환경
- h2에서 MySQL로 마이그레이션 적용
- 테스트 격리가 안되는 현상 발생 (기존 테스트 실패)
해결방법
- 프로덕션 코드는 build가 통과한다. → 엔티티와 DB스키마가 일치한다 → 테스트에 Flyway 스키마를 적용할 필요가 없다
- Flyway + MySQL : 배포서버, 로컬서버 프로덕션 코드
- h2 : 배포서버, 로컬서버 테스트 코드
3. 테스트 코드 yml 설정
- flyway.enabled=false를 꼭 설정하자
4. 42001 에러
기존 테이블 내용과 새롭게 추가된 스키마 사이 추가되는 과정에서 중복된 내용이 있거나 관리되는 스키마 내용이 다를 때 에러가 발생한다.
- drop table flyway_schema_history 를 적용, ddl auto를 validate 한 뒤 실행해보자.
'공부 > 프로젝트' 카테고리의 다른 글
JPA에서 낙관적 락을 적용해보자 (1) | 2022.10.27 |
---|---|
restdocs를 사용해보자 (0) | 2022.07.29 |
젠킨스 pipeline를 설정해보자 (0) | 2022.07.26 |
[지원플랫폼] 플래닝포커를 해보자 (0) | 2022.07.25 |
DB 서버를 연동해보자 (0) | 2022.07.25 |
댓글