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. Oracle 11でSELECT文の実行結果をCSV/TSV出力する

comments powered by Disqus