Spring Boot + Flywayで複数のDatasourceにそれぞれ別のmigrationを実行する


やりたいこと

  • Spring Bootアプリケーションで複数のDataSourceを作成する
  • Flywayでマイグレーションをする
  • 複数のDataSourceに対してそれぞれ別のマイグレーションを実行する

環境

  • OpenJDK 11
  • Spring Boot 2.4.3
  • Flyway 7.1.1
  • (Kotlin 1.4.30)

ポイント

  • Springに複数のDataSourceを作成する
  • そのうちの1つを @Primary に設定することで、こちらへのマイグレーションは自動で実行させる
  • それ以外のDataSourceへのマイグレーションは手動で設定してあげる

設定方法

前提

データベースは2つ作成済み。それぞれ「origin」と「dest」と呼び分ける。

datasourceの設定

application.ymlで複数のデータソースを設定する

application.ymlで以下のようにoriginとdestの複数のデータソースを設定してあげます

application.yml
spring:
  datasource:
    origin:
      url: jdbc:mysql://127.0.0.1:3316/main_db
      username: scott
      password: tiger
    dest:
      url: jdbc:mysql://127.0.0.1:3317/main_db
      username: scott
      password: tiger

Spring boot側のDataSourceの設定

適当な場所にOriginとDestのDataSourceのBeanをそれぞれ定義してあげます。
ポイントは、どちらか一つ(今回の場合ではOrigin)を @Primary として設定することです。
これをやることでPrimary側のDatasourceへのマイグレーションに関しては特別な設定に必要なく動作します。


@Component
@ConfigurationProperties(prefix = "spring.datasource.origin")
class OriginConfiguration {
    lateinit var url: String
    lateinit var username: String
    lateinit var password: String

    @Bean(name = ["origin"])
    @Primary // <= これ大事
    fun dateSource(): DataSource =
        DataSourceBuilder
            .create()
            .url(url)
            .username(username)
            .password(password)
            .build()
}
@Component
@ConfigurationProperties(prefix = "spring.datasource.dest")
class DestConfiguration {
    lateinit var url: String
    lateinit var username: String
    lateinit var password: String

    @Bean(name = ["dest"])
    fun dateSource(): DataSource =
        DataSourceBuilder
            .create()
            .url(url)
            .username(username)
            .password(password)
            .build()
}

Flywayの設定

migrationファイルの置き場

以下のようにdb.migrationをdistとoriginに分けています。

Origin(Primary)側のmigrationの設定

上述の通りこちらに関しては設定クラスを作成する必要はありませんが、migrationファイルのロケーションだけapplication.ymlで明示してあげる必要があります。
デフォルトではdb/migrationになっているので、これをdb/migration/originに変更します。

application.yml
spring:
  datasource:
    origin:
      url: jdbc:mysql://127.0.0.1:3316/main_db
      username: scott
      password: tiger
    dest:
      url: jdbc:mysql://127.0.0.1:3317/main_db
      username: scott
      password: tiger
  flyway:
    locations: "classpath:db/migration/origin" # <= 追記

Dest側のmigrationの設定

最後に、Destに対するmigrationの設定クラスを作成します。


@Configuration
class FlywayMigrationConfiguration(
    @Qualifier("dest")
    private val destDataSource: DataSource
) {
    @PostConstruct
    fun migrateFlyWay() {
        Flyway
            .configure()
            .dataSource(destDataSource)
            .locations("db.migration.dest")
            .target(MigrationVersion.LATEST)
            .load()
            .migrate()
    }
}

実行

上記の状態でアプリケーションを起動すると、意図通りにdestとoriginにそれぞれmigrationが実行されます。