Spring BootアプリにFlywayを導入してみた

Spring Bootのアプリで、ローカルDBのスキーマをうまく管理するためにFlywayを導入してみたのでメモ。

Flywayを選んだ理由

Flywayを選んだ理由は主に以下の辺り。

  • DB設計・管理コストの削減
  • フレームワーク・OSSによる一般的な枠組みの採用
  • 学習コストが低い、シンプルな構成
  • できるだけXMLレスな設定

他にはLiquibaseもあるが、XMLレスにしたいので回避。
MyBatis Migrationsも気になったけど、Flywayのほうがバージョン管理が楽そうでした。
FlywayはSpring Bootの依存関係に含まれていて、Auto Configurationにも対応してます。

Maven設定

pom.xmlに以下を追加。

<dependency>
  <groupId>org.flywaydb</groupId>
  <artifactId>flyway-core</artifactId>
</dependency>

マイグレーションスクリプトの配置

マイグレーションスクリプトの配置場所はspring.flyway.locationsで指定できるが、Spring Bootではデフォルトで以下のように指定されている。

spring.flyway.locations=classpath:/db/migration

そのため特にプロパティファイルには指定せず、/resources/db/migration/以下にスクリプトを配置していけばよい。
マイグレーションスクリプトはV1_0_0__baseline.sqlのようなファイル名にすると、バージョンが1.0.0で、descriptionがbaselineになる。

開発・テスト用のデータを投入する

開発時やテスト用の自動投入するには、プロファイル毎に異なるプロパティを参照させればよさそう。
Spring Boot Reference Guide の Execute Flyway Database Migrations on Startupにあるように、プロファイル毎のプロパティで設定を分け、開発時のプロファイル(dev)でのみ以下のように指定する。

spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration

あとはサンプルデータの投入処理を/dev/db/migration/以下に配置すればよい。

ベースラインの設定

ベースラインとは、既存のDBスキーマがどのバージョンに相当するかを指定するもの。
これまでFlywayを使っていなかったDBスキーマでは明示的に指定する必要がある。

今回はSpring Bootアプリのプロパティで、以下を指定。
プロパティの内容はほぼFlywayの環境変数そのままなので、FlywayのEnvironment Variablesが詳しい。

spring.flyway.baseline-version=1.0.0
spring.flyway.baseline-on-migrate=true

前者はベースラインのバージョンを指定する。
デフォルトは1だが、今回はV1_0_0__baseline.sqlのようなファイル名でマイグレーションスクリプトを作っていく予定なので、1.0.0を指定。

後者はメタデータを持たないが空でないDBだった場合、マイグレーション実行時にベースラインを実行してよいかどうかを設定する。
つまり、今までFlywayを使ってこなかったDBスキーマに対し、ベースラインを自動的に適用してくれる。

なお、ベースラインが実行された時、そのマイグレーションスクリプトは実行されない。
例えばspring.flyway.baseline-version=1.0.0を指定した場合、存在するDBに対してV1_0_0__baseline.sqlは実行されない。

マイグレーション時のエラー検知設定

マイグレーション実行時、エラーと判定するかどうかを設定する項目があるようで、Flywayの公式ドキュメントで以下の4つが記載されている。

  • FLYWAY_IGNORE_MISSING_MIGRATIONS
  • FLYWAY_IGNORE_IGNORED_MIGRATIONS
  • FLYWAY_IGNORE_PENDING_MIGRATIONS
  • FLYWAY_IGNORE_FUTURE_MIGRATIONS

これらはSpring Bootでは、以下の設定がデフォルトになっている。

spring.flyway.ignore-future-migrations=true # Whether to ignore future migrations when reading the schema history table.
spring.flyway.ignore-ignored-migrations=false # Whether to ignore ignored migrations when reading the schema history table.
spring.flyway.ignore-missing-migrations=false # Whether to ignore missing migrations when reading the schema history table.
spring.flyway.ignore-pending-migrations=false # Whether to ignore pending migrations when reading the schema history table.

ただ、これらの条件がいまいちよく分からなかったので、実際に試しつつ考察。

FLYWAY_IGNORE_FUTURE_MIGRATIONS

再現例

  1. Spring Bootの構成にマイグレーション用のスクリプトV1, V2を配置して起動→V1, V2が適用される
  2. その後V2のSQLが存在しない状態で、再度起動する

この時、spring.flyway.ignore-future-migrationsの値により、以下のようになる。

  • true:エラーとならずに無視される
  • false:エラーとなり停止する

考察

アプリ/システムのDBバージョンが低い状態、すなわちダウングレードさせた状態を許容するかどうかのチェック。
最新版で問題が起きたとき等、試しにダウングレードして動かすような使い方が想定されるならtrue。
ただし最新版でスキーマを大きく変更(特にカラムの削除や移動)したり、制約条件を追加した場合には、そもそもダウングレードしてもエラーになる可能性があるので注意。

FLYWAY_IGNORE_IGNORED_MIGRATIONS

再現例

  1. Spring Bootの構成にマイグレーション用のスクリプトV1, V2を配置して起動→V1, V2が適用される
  2. その後V1.1を追加した構成で、再度起動する

この時、spring.flyway.ignore-ignored-migrationsの値により、以下のようになる。

  • true:エラーとならずに無視される。V1.1も実行されない
  • false:エラーとなり停止する

考察

適切な順序で適用できないマイグレーションスクリプトが存在するかどうかのチェックをしている。
DBスキーマのカラム名変更や削除を行わず、カラムだけを追加していくような場合はtrueでも問題ないと思われる。

もし順番を気にせず実行して問題ない場合はspring.flyway.out-of-order=trueを指定すれば実行される(はず)。

FLYWAY_IGNORE_MISSING_MIGRATIONS

再現例

  1. Spring Bootの構成にマイグレーションスクリプトV1, V2, V3を配置して起動→V1, V2, V3が適用される
  2. その後V2を削除し、V2が存在しない構成で再度起動する

この時、spring.flyway.ignore-missing-migrationsの値により、以下のようになる。

  • true:エラーとならずに無視する
  • false:エラーとなり停止する

考察

アプリ/システムのマイグレーションスクリプトに欠落がないかどうかのチェックをしている。
DBスキーマのカラム名変更や削除を行わず、カラムだけを追加していくような場合はtrueでも問題ないと思われる。

FLYWAY_IGNORE_PENDING_MIGRATIONS

どういうケースが当てはまるのかまだ理解できておらず、具体例を確認できていない。

以下を試してみたが、本エラーは発生せず。

  • V1, V2, V3を配置して起動したら、V3までマイグレーションされるので、いずれもPendingにはならない
  • V1, V2, V3を配置してspring.flyway.target=2を指定しても、V3は認識されず、Pendingにならない。

その他:リピータブルマイグレーション

まだ使用していないが、リピータブルマイグレーションという枠組みもある。
マイグレーション毎に毎回実行されるため、ビューの再作成などに使用する(らしい)。

その他:DDL/DMLとの優先順位

Spring Bootでは、以下のプロパティで指定したSQLを自動的に実行することができるようになっている。

spring.datasource.schema= # Schema (DDL) script resource references.
spring.datasource.data= # Data (DML) script resource references.

どうやらこれらはFlywayのマイグレーション処理よりも先に実行されるようなので、それを考慮した構成にする必要がある模様。

所感

Flyway(というかDBマイグレーション)は前々から目をつけていたものの、ようやく導入。
DBマイグレーションに関する実装を設定ファイルとSQLファイルで完結できるのは大きなメリット。
構成がシンプルで、学習コストが低そうな点もおおよそ想定通り。

エラーレベルに関してはまだ完全に把握できていない部分もあるが、基本的にはデフォルトの設定で運用し、エラーが出たら開発や運用の体制に応じて見直せば問題なさそう。

参考

関連記事


  1. Spring Web MVCのAuto Configuration周辺のクラス図を描いてみた
  2. ModelMapperで1対1に対応しないフィールドのマッピング
  3. Spring BootをGoogle App Engineフレキシブル環境へデプロイする
  4. Spring BootをGoogle App Engineスタンダード環境にデプロイする
  5. 一部のパスだけSpring SecurityのCSRF対策を無効化する
  6. Spring Boot アノテーション集
  7. データベースを参照してシステム連携する際に気をつけること

comments powered by Disqus