[코프링] flyway 이용해서 spring-boot mysql 세팅하기

     

flyway

 

스프링 부트에서 JPA 쓰면 자동으로 DB가 마이그레이션 되기는 하는데, 이력이 남지 않아 관리가 힘들다. 그래서 따로 툴을 사용하여 마이그레이션 버전을 관리를 하는데, 가장 많이 쓰이는 것이 flyway인 것 같다. 

 

전에 한번 사용해보긴 했는데 너무 오래돼서 까묵었다.. ㅋㅋ 이번에 프로젝트 세팅하면서 기록해놓으려고 한다.

 

일단 mysql에 연동할 계획이기 때문에 DB를 띄울 dockerfile을 만들어놓는다.

 

version: "3"
services:
  mobo-db:
    image: mysql:8.0
    container_name: mobo-db
    ulimits:
      nofile:
        soft: 20000
        hard: 40000
    volumes:
      - /opt/persistent-storage/mysql/:/var/lib/mysql/
    environment:
      - MYSQL_ROOT_PASSWORD=asdf
      - MYSQL_ROOT_HOST=%
    ports:
      - "3306:3306"

docker로 mysql을 띄워놓고 시작하자.

 

참고로 gradle에 kotlin 기반이다.

gradle 파일에 flyway를 추가한다.

implementation("org.flywaydb:flyway-mysql")

 

application.yml은 다음과 같이 추가한다.

 

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: asdf
    username: root
    url: jdbc:mysql://localhost:3306/mobo?serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true

  flyway:
    enabled: true
    baseline-on-migrate: true
    baseline-version: 1
    url: jdbc:mysql://localhost:3306/mobo
    user: root
    password: asdf

  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MySQL8Dialect
    generate-ddl: false # DDL 생성 여부
    hibernate:
      ddl-auto: validate # ddl 전략 설정 none, update, validata, create, create-drop
      use-new-id-generator-mappings: false #  Hibernate의 id 생성 전략을 그대로 사용
    show-sql: true # sql 출력
    properties:
      hibernate:
        enable_lazy_load_no_trans: true # LAZY 로드를 default로 설정
        format_sql: true # sql을 보기 좋게 출력

 

jpa에서 generate-ddl을 false로 해야 jpa에서 테이블을 생성하지 않는다. 

 

이제 migration 파일을 만들면 되는데 resource/db/migration 폴더 안에 넣으면 된다.

 

# ~/src/main/resources/db/migration/V1__init.sql
DROP TABLE IF EXISTS `messages`;
CREATE TABLE IF NOT EXISTS `messages` (
    `id` bigint NOT NULL AUTO_INCREMENT,
    `message` varchar(512) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

 

파일 이름은 V1__{some work}.sql 형태로 앞에 프리픽스 영문자 + 숫자로 버전을 관리하고 뒤에 작업명을 적으면 된다. 그럼 알아서 실행할 때 순서대로 실행함.

 

mysql 8 버전이랑 연동하다보니 flyway 버전이랑 약간 안 맞을 수 있는데 아래 flyway-mysql로 입력하니까 잘 된다.

implementation("org.flywaydb:flyway-mysql")

docker로 DB를 띄우고 나서는 mobo라는 디폴트 스키마를 만들어줘야 한다. 즉, DB를 그냥 만들기만 하고 바로 실행해버리면 스키마에 접속 못한다는 에러가 남. 그래서 수동으로 mobo라는 schema를 만들어주었고, 그다음 프로젝트를 실행하면 자동으로 migration을 진행한다. 

 

mobo를 만들어줘야함

 

이제 프로젝트를 실행하면 두 개의 테이블이 생기는데, 하나는 내가 만든 messages테이블이고 하나는 flyway에서 마이그레이션 버전을 관리하는 flyway_schema_history 테이블이다.

 

테이블 두개 생김

이 테이블에는 여태까지 실행한 마이그레이션 파일들을 저장하고 있고, 다음에 실행할 때 이 다음버전의 마이그레이션을 실행할 수 있도록 도와준다.

 

실제로 프로젝트를 시작하고 로그를 보면 flyway가 자동으로 마이그레이션을 진행하는 로그를 볼 수 있다.

중간에 보면 Migrate를 자동으로 하는 걸 볼 수 있다.

 

추가적으로 테이블을 몇개 더 만들기 위해 마이그레이션 파일을 하나 더 만들어보자.

 

CREATE TABLE IF NOT EXISTS `main_categories`
(
    `id`    bigint       NOT NULL AUTO_INCREMENT,
    `name`  varchar(512) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb3;

CREATE TABLE IF NOT EXISTS `sub_categories`
(
    `id`    bigint       NOT NULL AUTO_INCREMENT,
    `name`  varchar(512) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb3;

CREATE TABLE IF NOT EXISTS `tag_messages`
(
    `id`         bigint      NOT NULL AUTO_INCREMENT,
    `tag_name`       varchar(64) NOT NULL,
    `message_id` bigint      NOT NULL,
    FOREIGN KEY (`message_id`) REFERENCES messages (`id`) ON UPDATE CASCADE ON DELETE RESTRICT,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb3;

CREATE INDEX idx_tag_name ON tag_messages (`tag_name`);

CREATE TABLE IF NOT EXISTS `category_messages`
(
    `id`         bigint      NOT NULL AUTO_INCREMENT,
    `main_category_id` bigint      NOT NULL,
    `sub_category_id` bigint      NOT NULL,
    `message_id` bigint      NOT NULL,
    FOREIGN KEY (`main_category_id`) REFERENCES main_categories (`id`) ON UPDATE CASCADE ON DELETE RESTRICT,
    FOREIGN KEY (`sub_category_id`) REFERENCES sub_categories (`id`) ON UPDATE CASCADE ON DELETE RESTRICT,
    FOREIGN KEY (`message_id`) REFERENCES messages (`id`) ON UPDATE CASCADE ON DELETE RESTRICT,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb3;

CREATE INDEX idx_main_category_and_sub_category ON category_messages (`main_category_id`, `sub_category_id`);

 

테이블을 여러개 만들고, FK도 좀 넣고, 인덱스도 좀 넣었다. 문법은 그냥 mysql문법으로 하니까 된다.

 

버전 2로 변경

테이블이 여러개 생기고 버전도 2로 올라갔다. 구욷..

 

만약 이전 것이 변경돼서 다시 해야 되면 이 history 테이블을 날리고 재실행하면 된다. 그냥 schema를 다 날리고 해도 깔끔~

 

 

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY