Flyway とは

DB の状態をバージョン管理する為のツールで Spring Boot で簡単に使用することができる。 IntelliJ IDEA で新規プロジェクトを作成する時に依存関係に Flyway を含めると以下が build.gradle に追加される:

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

Spring Boot の場合 application.yaml に DB 設定を行うことが必須だ。 SQLite の場合以下のように定義しておく:

spring:
  datasource:
    url: jdbc:sqlite:./db.sqlite3
    driverClassName: org.sqlite.JDBC

Flyway のマイグレーションファイルは (クラスパス)/db/migration 以下に V(バージョン番号)__(説明).sql の形式で置く。 バージョン番号は公式的には単調増加自然数 (1, 2, ...) のようだが V1_0_2__(説明).sql のようにするといわゆるマイナーバージョンとリファクタリング番号を記録する (v1.0.2 的な) ことができるようだ。

Spring Boot の場合アプリケーションを実行すると (クラスパス)/db/migration 以下のマイグレーションが自動で走り、今までのマイグレーションの状態は DB の中に flyway_schema_history テーブルが作成されて管理される。 この flyway_schema_history テーブルの中を見てみるとどこまでマイグレーションが適用されているか簡単に確認できる。

Flyway の詳しい解説は Flyway使い方メモが分かりやすかった。 SQL ファイルだけでなく Java コードでマイグレーションを記述することができるらしい。 以下、上記ページで解説されていなかった「既存 DB に対するマイグレーション定義」に関して書く。

既存の DB を元にマイグレーションを行う場合

Flyway のマイグレーションはデフォルトでは DB 設計を一から行って新規で作成するアプリケーションの場合が想定されている。 つまり初めは空のデータベースが用意されており V1__Initial.sql などというファイルを用意し初期テーブルを定義し、その後 V2__Add_delete_flag などといった感じで初期テーブルに変更を加えていくイメージだ。

だが「既にテーブルが定義されている DB に対しマイグレーションを行った場合」 (まだ flyway_schema_history が定義されておらず初期投入扱い) は以下の様にエラーが表示される:

Caused by: org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "main" without schema history table! Use baseline() or set baselineOnMigrate to true to initialize the schema history table.

これを回避するためにベースライン (初期状態のバージョン番号) を Flyway に教える必要がある。 application.yaml に以下を定義する:

spring:
  flyway:
    baseline-on-migrate: true
    baseline-version: 1
    baseline-description: Initial

spring.flyway.baseline-on-migratetrue の場合既存 DB にマイグレーションを行った場合に spring.flyway.baseline-version まで適用済みとみなしてくれる。 つまり前述の例の場合 V1__Initial.sql は実行されずに V2__Add_delete_flag のみが適用される。 spring.flyway.baseline-description に定義した文字列はマイグレーション実行後に flyway_schema_history.description のベースラインまで適用されたことを示す文字列として挿入される。 初期値 (未定義の場合) は << Flyway Baseline >> のようなのでこのままでも問題ないと思われる。

このあたりの設定の解説は Flyway 公式に書いてある (英語)。