Flyway

IMKUNYOUNG·2023년 10월 25일
0

DB 마이그레이션

목록 보기
1/1

Flyway

  • 오픈 소스 데이터베이스 마이그레이션 툴
  • DB 형상 관리
  • 형상 관리는 소프트웨어의 변경사항을 체계적으로 추적하고 통제하는 툴
  • Flyway라는 툴로 DB 변경을 관리


Flyway는 어떤 상황에서?

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

}

기능 추가에 따른 컬럼 추가, 변경

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

}

이렇게 개발하다가 DB 스키마가 변경되어야 할 때 우리는 아래를 고려함

  1. spring.jpa.hibernate.ddl-auth = create or update
키워드내용
create이전 기록을 날리기 때문에 배포 환경에서 못씀
update테이블을 수정하지 않고, 부족한 부분만 추가함

update 예시) Member라는 테이블을 User 로 수정했을 시, 데이터베이스에는 Member라는 테이블이 User로 변경되는 것이 아니라 User라는 테이블이 새로 추가됨. 컬럼명 변경 시에도 마찬가지

  1. 각 배포 환경을 돌아다니면서 직접 schema 변경하기
  • 이 또한 현실적인 어려움이 있음

Flyway의 버전 관리




![](https://velog.velcdn.com/images/gun_123/post/6308fd22-e511-4612-b554-3354dbdce963/image.png) ![](https://velog.velcdn.com/images/gun_123/post/4a6455fe-3355-49f8-a1ec-30fd8037da02/image.png)

주의할 점
변경 기록 테이블이나 Migration Script 파일을 지우거나 변경하면 안됨



실습

# build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.flywaydb:flyway-core'
    implementation 'org.flywaydb:flyway-mysql'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.mariadb.jdbc:mariadb-java-client:3.2.0'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}
# com/example/flywaypoc/FlywayPocApplication.java
package com.example.flywaypoc;

import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class FlywayPocApplication {

    private final EntityManager em;

    public FlywayPocApplication(EntityManager em) {
        this.em = em;
    }


    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(FlywayPocApplication.class);
        app.setWebApplicationType(WebApplicationType.NONE);
        ConfigurableApplicationContext run = app.run(args);

        FlywayPocApplication flywayPocApplication = (FlywayPocApplication)run.getBean("flywayPocApplication");

        Member member = new Member("sample");
        flywayPocApplication.save(member);

    }

    @Transactional
    public void save(Member member) {
        em.persist(member);
    }

}
# src/main/java/com/example/flywaypoc/Member.java
package com.example.flywaypoc;


import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

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


    public Member(String sample) {
        this.name = sample;
    }

    public Member() {

    }
}
# src/main/resources/application.properties

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://34.121.193.102:3306/flyway
spring.datasource.username=root
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.generate-ddl=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.flyway.enabled=true

spring.flyway.baseline-on-migrate=true
# src/main/resources/db/migration/V1__init.sql
drop table if exists member;

create table member(
    id bigint auto_increment,
    name varchar(255),
    primary key (id)
);



실행 시

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.5)

2023-10-25T11:40:09.329+09:00  INFO 18724 --- [           main] c.e.flywaypoc.FlywayPocApplication       : Starting FlywayPocApplication using Java 17.0.2 with PID 18724 (C:\Users\ur2ku\OneDrive\바탕 화면\WORKSPACE\liberty52\Flyway-POC\build\classes\java\main started by ur2ku in C:\Users\ur2ku\OneDrive\바탕 화면\WORKSPACE\liberty52\Flyway-POC)
2023-10-25T11:40:09.332+09:00  INFO 18724 --- [           main] c.e.flywaypoc.FlywayPocApplication       : No active profile set, falling back to 1 default profile: "default"
2023-10-25T11:40:09.682+09:00  INFO 18724 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-10-25T11:40:09.697+09:00  INFO 18724 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 10 ms. Found 0 JPA repository interfaces.
2023-10-25T11:40:09.962+09:00  INFO 18724 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.16.3 by Redgate
2023-10-25T11:40:09.962+09:00  INFO 18724 --- [           main] o.f.c.internal.license.VersionPrinter    : See release notes here: https://rd.gt/416ObMi
2023-10-25T11:40:09.962+09:00  INFO 18724 --- [           main] o.f.c.internal.license.VersionPrinter    : 
2023-10-25T11:40:09.969+09:00  INFO 18724 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-10-25T11:40:11.201+09:00  INFO 18724 --- [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection org.mariadb.jdbc.Connection@622fdb81
2023-10-25T11:40:11.202+09:00  INFO 18724 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-10-25T11:40:11.209+09:00  INFO 18724 --- [           main] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:mariadb://34.121.193.102/flyway (MariaDB 11.1)
2023-10-25T11:40:12.952+09:00  WARN 18724 --- [           main] o.f.c.internal.database.base.Database    : Flyway upgrade recommended: MariaDB 11.1 is newer than this version of Flyway and support has not been tested. The latest supported version of MariaDB is 10.10.
2023-10-25T11:40:14.512+09:00  INFO 18724 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:01.364s)
2023-10-25T11:40:16.955+09:00  INFO 18724 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `flyway`: 1
2023-10-25T11:40:17.144+09:00  INFO 18724 --- [           main] o.f.core.internal.command.DbMigrate      : Schema `flyway` is up to date. No migration necessary.
2023-10-25T11:40:17.941+09:00  INFO 18724 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-10-25T11:40:17.983+09:00  INFO 18724 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.2.13.Final
2023-10-25T11:40:17.985+09:00  INFO 18724 --- [           main] org.hibernate.cfg.Environment            : HHH000406: Using bytecode reflection optimizer
2023-10-25T11:40:18.178+09:00  INFO 18724 --- [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
2023-10-25T11:40:18.473+09:00  WARN 18724 --- [           main] org.hibernate.orm.deprecation            : HHH90000025: MariaDBDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
2023-10-25T11:40:19.307+09:00  INFO 18724 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
2023-10-25T11:40:20.170+09:00  INFO 18724 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-10-25T11:40:20.366+09:00  INFO 18724 --- [           main] c.e.flywaypoc.FlywayPocApplication       : Started FlywayPocApplication in 11.295 seconds (process running for 11.742)
2023-10-25T11:40:21.279+09:00  INFO 18724 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2023-10-25T11:40:21.285+09:00  INFO 18724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2023-10-25T11:40:21.444+09:00  INFO 18724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.



새로운 기능 개발 시

age 컬럼을 추가

실행 시

아래의 마이그레이션 스크립트 파일을 추가

# src/main/resources/db/migration/V2__add_age_in_member.sql
ALTER TABLE member ADD COLUMN age integer DEFAULT 0

-> 변경 부분만!



Migration Script 네이밍

  • repeatable은 버전에 상관없이 매번 실행되는 스크립트
    ex) 테스트 편의를 위해, Member 더미 데이터를 매번 추가해야 하는 경우


migration 파일 경로 설정

  • migration 파일 경로를 수정하고자 할 때,
  • Default는 spring.flyway.locations=classpath:db/migration
  • db/migration/test로 변경하고자 할 시spring.flyway.locations=classpath:db/migration/test

  • 벤더에 따라 분리하고자 할 때,

  • spring.flyway.locations=classpath:db/migration/{vendor}

  • local에서만 특히 시드 값을 넣어주고 싶을 때,

  • spring.flyway.locations=classpath:db/migration/{vendor},classpath:db/seed



기존 데이터가 있는 상황에서 Flyway 적용하기

참고: Flyway DB 마이그레이션 / 기존 데이터가 있는 상황에서 Flyway 적용하기




0개의 댓글