본문 바로가기

flyway

Flyway란 무엇이고 어떻게 사용하는 것 일까 ?

728x90

Flyway

 

Flyway는 DB의 형상관리를 목적으로 하는 툴이다.

 

1. DB Migration 필요한 것일까?

배포를 했다고 가정을 해보자,

유지 보수 중 스키마 구조가 바뀌게 된다면 그 상황에서 어떻게 대처할 것인가 ?

 

예제를 통해 알아보겠습니다.

현재 유지보수 중인 Member Entity가 다음과 같다고 가정하자

package com.example.dockercomposetest.entity;


import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

@Entity
@Getter
@Setter
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

}

하지만, 새로운요구사항이 추가되었다. hello_new_column필드를 추가해야한다.

그렇다면 Entity에서는 단순히 Private Integer hello_new_column을 추가하면 된다.

 

하지만 실제 DB상황에서 변화를 어떻게 처리할 것인가 ??? 가 문제된다.

 

 

방법1. DB서버에 들어가 테이블 직접수정한다.

 

해당 DB에 접속하여 다음의 스키마를 입력해준다 하지만 단점이 존재함,

 

ALTER TABLE Member ADD COLUMN hello_new_column INTEGER DEFAULT 0;

-실수하기 좋다.

-작업하기 번거롭다

-만약 데이터가 미리있고,Entity쪽만 변경(hello_new_column 추가), DB스키마를 수정하지 않았다면?

아래와 같은 에러가 발생한다.

Caused by: java.sql.SQLSyntaxErrorException: Unknown column

 

방법2. Flyway 툴을 사용하자

궁금적인 목표

- DB에 접속해서 TABLE을 직접 건들지 않으며, hello_new_column 컬럼 포함한 신규데이터를 저장한다.

-이전 컬럼이 포함되지 않은 데이터는 필드를 0으로 초기화한다.

-git으로 관리한다-> 파일로 관리할 수 있어야한다.

 

Flyway 사용법

 

1. 의존성 추가 build.gradle

 

 

dependencies {
    implementation('org.flywaydb:flyway-core:6.4.2')
}

 

 

2. 어플리케이션 설정 추가: application.yml

 

spring:
  flyway:
    enabled: true
    baselineOnMigrate: true
    locations: classpath:db/migration/{vendor},classpath:db/seed
  profiles: test
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;MODE=MySQL;
    username: sa
    password:

  h2:
    console:
      enabled: true

  jpa:
    database: h2
    database-platform: com.ss.camper.config.CustomMySQL5Dialect
    generate-ddl: false
    open-in-view: true
    hibernate:
      ddl-auto: validate

 

 

 

3. init 파일 추가:  resources/db/migration/

 

등록하려는 시점의 DB 스키마 구조를 입력해야 한다.

이 파일을 기준으로 flyway가 DB버젼 관리를 하게된다.

버전관리는 다음과 같이 V(숫자)__{설명}.sql으로 생각하면 된다.

 

V1__init_table.sql

DROP TABLE IF EXISTS Member;

CREATE TABLE member (
                        id BIGINT PRIMARY KEY AUTO_INCREMENT,
                        name VARCHAR(255) NOT NULL
);

 

엔티티변경

 

V2__add_new_column.sql

 

ALTER TABLE Member ADD COLUMN hello_new_column INTEGER DEFAULT 0;

 

버전관리는 어떻게 하는가?

Prefix

  • V(Versioned): 현재버전을 새로운 버전으로 업데이트
  • U(Undo): 현재 버전을 이전버전으로 되돌리는 경우
  • R(Repeatable): 버전에 관계 없이 매번 실행하는 경우

Version

스크립트의 버전을 이전보다 꼭 높게 적어야 한다.

  • V와 U는 버전을 명시한다.
  • R은 버전을 명시하지 않는다. (매번 실행되기 때문이다)

Separator

무조건 __(언더바 2개)로 작성

Description

스크립트 내용에 맞게 자유롭게 적는다.

단어 구분은 _(언더바 1개)로 한다.

 

트러블슈팅

테스트 환경에서의 Flyway 실패

1. h2 테스트 환경

  1. h2에서 jdbc:h2:mem:testdb;MODE=MYSQL 을 적용
  2. V1__init.sql의 engine=InnoDB default charset utf8mb4; 부분에서 에러가 발생함

해결방법

  • h2 문법으로 적용하면 성공이 됨 → 스키마를 h2, MySQL 둘다 관리해야 하기 때문에 적용X
  • 로컬 test DB를 MySQL로 변경

2. MySQL 테스트 환경

  1. h2에서 MySQL로 마이그레이션 적용
  2. 테스트 격리가 안되는 현상 발생 (기존 테스트 실패)

해결방법

  • 프로덕션 코드는 build가 통과한다. → 엔티티와 DB스키마가 일치한다 → 테스트에 Flyway 스키마를 적용할 필요가 없다
    • Flyway + MySQL : 배포서버, 로컬서버 프로덕션 코드
    • h2 : 배포서버, 로컬서버 테스트 코드

3. 테스트 코드 yml 설정

  • flyway.enabled=false를 꼭 설정하자

4. 42001 에러

기존 테이블 내용과 새롭게 추가된 스키마 사이 추가되는 과정에서 중복된 내용이 있거나 관리되는 스키마 내용이 다를 때 에러가 발생한다.

  • drop table flyway_schema_history 를 적용, ddl auto를 validate 한 뒤 실행해보자.

 

 

 

 

728x90