flyway를 통해 DDL 형상관리를 하자

김도현·2023년 8월 7일
0

flyway

flyway는 데이터베이스의 형상관리를 목적으로 하는 툴이다. 데이터베이스의 형상 관리란 어떤 것을 말할까? git을 통하영 우리가 코드를 관리하는 것의 데이터베이스 버전으로 볼 수 있다. git에서는 코드를 파일별로 로깅을 통해서 변화의 이력을 추적한다. flyway는 데이터베이스의 DDL의 이력을 쌓아서 DDL이 어떻게 변화되었는지 관리하는 툴로 사용할 수 있다.

위 이미지는 flyway 공식 홈페이지에 나와있는 이미지로 DDL 형상관리의 이해를 도와준다. 위 이미지를 보면 Axel과 Christian이 별개로 DDL을 만들고 있다. 그리고 서버로 배포할 때 자동화 빌드 과정에서 함께 통합하여 DDL을 실행되는 것이다. flyway를 잘 사용하면 이렇게 DDL을 관리할 수 있게 된다.

flyway는 다양한 방법으로 실행할 수 있다. 공식 사이트에 따르면 gradle, maven, CLI, 그리고 JAVA API이다. Spring Boot로 서버를 띄울 때 자동으로 DDL이 실행될 수 있도록 설정을 해보겠다. 이 방법은 JAVA API를 사용하는 것이다.

DB Migration

DB Migration의 필요를 모를 수 있다. 솔직히 나는 몰랐다. 배포 후 데이터를 관리해본 경험이 없었고, 유지 보수 스키마 구조가 바뀌는 상황에 어떻게 대처하는지 생각해본 적 없었다.

DB Migration의 필요성을 보여주는 상황을 하나 보여주겠다.

SampleEntity를 예제로 사용할 것인데, 배포가 이미 완료된 더 복잡하고 이미 쌓인 정보도 많은 데이터라고 상상해주길 바란다.

@Entity
public class SampleEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

이런 필드로 SampleEntity가 배포되고 데이터가 쌓였던 상황인데, 신기술을 개발하는 도중에 int age 라는 필드를 추가하게 되었다.

@Entity
public class SampleEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Integer age;
}

자, 이런 상황에서 당신은 어떻게 이 SampleEntity 변화를 처리할 것인가.

나는 배포 서버 DB에 직접 들어가서 테이블을 직접 수정해왔다. 그건 쉬운 작업이 아니다. 솔직히 엄청 귀찮다. 배포 후 기능을 추가하면서 스키마가 변경되는 일이 많았고, 매번 일일히 작업하는 게 번거로울 뿐 아니라 실수하기도 딱 좋다.

ALTER TABLE sample_entity ADD COLUMN age integer default 0

로컬에서 DB 변경 사항을 추가하는 것으로 배포 이후에는 알아서 관리될 수 있다면 얼마나 좋을까. 그냥 코드를 관리하는 것처럼 DB 변경 사항을 관리할 순 없을까?

Flyway 라는 툴을 사용하면 그걸 해소할 수 있다. Flyway를 사용하고 해결하는 과정을 천천히 보여주려고 한다.

적용 과정

예외 확인하기 : Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'age' in 'field list'

우선 sampleEntity 데이터를 미리 3개 넣어두었다. 이 상황에서 int age 필드가 추가하고 DB 스키마를 수정하지 않으면 SQL 에러가 뜨는 것을 확인하다.

이제 flyway를 적용한다.

궁극적인 적용 목표는 다음과 같다. (환경은 gradle, spring boot, mySql 를 기준으로 한다.)

  1. DB에 접속해서 table을 직접 건들지 않고, 나이를 포함한 신규 데이터를 저장한다.
  2. 동시에 이전 나이가 포함되지 않은 데이터는 나이 필드를 0으로 초기화한다.
  3. git으로 관리할 것이기 때문에, 해당 작업을 파일로 관리할 수 있어야 한다.

의존성 추가: build.gradle

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

어플리케이션 설정 추가: application.properties 혹은 application.yaml

#data source 설정 / 본인 환경에 맞게 수정해주세요.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:13306/flyway
spring.datasource.username=ecsimsw
spring.datasource.password=1234

#flyway 설정
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.flyway.enabled=true
spring.jpa.generate-ddl=false

#Spring boot 2 이상의 경우 아래 설정 추가
spring.flyway.baselineOnMigrate = true

init 파일 추가: resources/db/migration/V1__init.sql

flyway를 등록하려는 시점의 db 스키마 구조를 입력해야 한다. 이 파일을 기준으로 flyway가 DB 버전 관리를 하게 된다. 지우면 안된다.

# 이전 table를 지우고
drop table if exists sample_entity;

# 초기 스케마를 정의하고
create table sample_entity(
    id   bigint auto_increment,
    name varchar(255),
    primary key (id)
);

# history를 추가한다.
INSERT into sample_entity (name) values ('ecsimsw');
INSERT into sample_entity (name) values ('코기');
INSERT into sample_entity (name) values ('김진환');

스키마 구조 변경 사항 파일 추가 : resources/db/migration/V2__add_age.sql

이렇게 flyway를 적용한 시점(아직 age 사용 x)에서 작업을 하다가, 스키마 구조가 변경되는 상황(age)이 생겼다고 하자. 이때 변경 사항을 파일에 저장하는 것이다. 이때 파일명은 flyway의 규칙을 따라야 한다. 어렵다면 일단 'V {숫자}__{설명}. sql' 정도만 알고 넘어가자

다시 예제로 돌아와 'resources/db/migration/V2__add_age.sql'을 작성할 것이다. 파일에 스키마 변경 사항을 작성해주는 것이다. 마찬가지로 파일 위치와 파일명에 유의하길 바란다.

ALTER TABLE sample_entity ADD COLUMN age integer default 0

이렇게 하고 다시 age를 포함한 데이터를 추가하면 이제는 에러 없이 잘 들어감을 확인할 수 있다. 이제는 개발 도중 스키마가 변경되면 직접 배포 서버의 DB를 들어가 스키마를 변경하지 않고, 변경 사항을 코드로 관리할 수 있게 된다.

flyway_schema_history 확인하기
마지막으로 DB에 저장된 flyway_schema_history (flyway를 사용하면 자동으로 해당 스키마가 추가됨)를 확인한다. V1_init.spl 과 V2_add_dage.sql이 히스토리로 저장된 것을 확인할 수 있다.

마무리

JAVA API 방법은 여러대의 서버가 돌아가는 클라우드 서버 환경보다는 로컬에서 1대만 띄우는 환경에 적합하다. flyway는 여러가지 Java API 방법 뿐만 아니라 gradle, maven, CLI와 같은 방법을 제공하는데 환경에 맞춰서 적절하게 사용하는 것을 추천한다.

출처
https://sabarada.tistory.com/193
https://www.blog.ecsimsw.com/entry/Flyway%EB%A1%9C-DB-Migration

profile
Just do it

0개의 댓글