모종닷컴

spring boot r2dbc + flyway 본문

Programming/Spring

spring boot r2dbc + flyway

모종 2023. 6. 24. 16:24
반응형

spring boot r2dbc와 flyway를 같이 사용하니 flyway가 실행되지 않았던 문제가 있었습니다. 이에 대한 해결법과 원인에 대해 간단하게 공유드립니다.

r2dbc

반응형 프로그래밍을 통해 관계형 데이터베이스와 비동기적으로 통신하기 위한 스펙입니다. spring-boot-r2dbc는 이러한 r2dbc 스펙을 기반으로 만들어진 spring boot 프레임워크 모듈입니다.

flyway

Git이 코드 버전 관리 시스템이라면 flyway는 데이터베이스의 버전 관리 툴 정도로 보시면 될 것 같습니다. 좀 더 풀어서 설명하면 개발자가 애플리케이션에 변경과 관련된 SQL 스크립트를 만들어 배포하면 애플리케이션이 실행될 때 Flyway가 타깃 데이터베이스에 이 SQL을 대신 실행시킵니다. 이렇게 함으로써 애플리케이션과 데이터베이스 호환을 신뢰할 수 있습니다. 

예를 들어 엔티티 클래스가 있고 이 엔티티 클래스에 A라는 필드를 추가했다고 가정합니다. 그렇다면 이와 대응되는 sql(= 테이블에 필드 추가하는 쿼리)이 데이터베이스에 적용되어 있어야 애플리케이션이 정상적으로 동작할 텐데요. 이 SQL 스크립트를 애플리케이션에 작성해서 넣어두면 애플리케이션이 실행될 때 Flyway가 데이터베이스에 이 SQL 스크립트를 실행시킬 테니 애플리케이션 <-> 데이터베이스의 호환이 딱 맞아떨어지는 거죠.

spring-boot-r2dbc & flyway를 같이 사용하기

 이 두 가지를 함께 사용할 때 주의해야 할 부분이 있습니다. 먼저 spring-boot에는 자동 설정을 위해 spring-boot-autoconfigure라는 모듈이 존재합니다. 그리고 이 프로젝트 중에는 FlywayAutoConfiguration이라는 코드가 존재합니다. 이는 스프링 부트가 실행될 때 Flyway에 대한 설정을 자동으로 하기 위한 코드입니다. 저희가 .properties 파일 혹은 .yml 파일에 몇 가지 프로퍼티만 설정해 주면 되는 이유도 이러한 auto configure 클래스가 있기 때문입니다.

다시 FlywayAutoConfiguration 코드를 보면 몇 가지 조건이 주어집니다. 여기서 @Conditional 어노테이션을 보면 FlywayDataSourceCondition이라는 게 보이는데 이는 스프링 부트에서 Flyway와 관련된 설정을 조건부로 활성화하기 위한 조건 클래스입니다. 

FlywayDataSourceCondition 클래스를 보면 다시 조건과 관련된 어노테이션을 볼 수 있는데 DataSource 빈이 있어야 하고, spring.flyway.url이라는 프로퍼티가 설정되어 있어야 한다고 돼있습니다. 

문제는 여기서 발생합니다. spring-boot-r2dbc는 DataSource를 빈으로 등록하지 않습니다. DataSource는 전통적인 JDBC와 관련된 인터페이스로 블록킹 스펙이기 때문에, spring-boot-r2dbc에서는 DatabaseClient라는 논블럭킹 IO 인터페이스를 사용합니다. 

이러한 이유로 spring-boot-r2dbc와 flyway를 같이 사용할 때 flyway auto configure가 동작하지 않습니다. 따라서 개발자가 수동으로 flyway를 설정 및 마이그레이션을 호출해주어야 합니다.

수동으로 Flyway 실행시켜 주기

방법은 간단합니다. 아래와 같이 Configuration 클래스를 등록해 주시면 됩니다.

@Configuration
@EnableConfigurationProperties(FlywayProperties::class)
class FlywayConfig {

    @Bean(initMethod = "migrate")
    fun flyway(flywayProperties: FlywayProperties): Flyway {
        return Flyway.configure()
            .dataSource(flywayProperties.url, flywayProperties.user, flywayProperties.password)
            .locations(*flywayProperties.locations.toTypedArray())
            .table(flywayProperties.table)
            .baselineOnMigrate(true)
            .outOfOrder(true)
            .load()
    }
}

프로퍼티에는 아래와 같이 구성했습니다. 필요 없는 프로퍼티나 추가적인 프로퍼티가 있다면 따로 설정해야 합니다.

spring:
  flyway:
    url: jdbc:mysql://127.0.0.1:3306/test
    user: tester
    password: password
    locations: classpath:db/migration/all, classpath:db/migration/local
    table: flyway_schema

또 주의할만한 부분은 flyway.url에 jdbc 드라이버를 사용하고 있습니다. flyway에 issue가 19년도쯤부터 떠있는데 아지까지는 별다른 지원이 없는 것 같습니다.

댓글 중에 한 유저가 r2dbc-migrate라는 프로젝트를 하나 만들어서 23년 때까지 계속 커밋이 있는 걸 확인은 해봤지만 저는 사용은 아직 안 해봤습니다.

 

반응형