この記事から得られる知識
- Flywayの基本概念と、データベースマイグレーションがなぜ重要なのかを理解できる。
- MavenやGradleを使ったJavaプロジェクト(特にSpring Boot)へFlywayを導入し、基本的な設定を行う方法がわかる。
- バージョニングされたマイグレーションとリピータブルマイグレーションの命名規則を学び、SQLファイルを作成・管理できるようになる。
migrate
,info
,validate
,clean
,baseline
,repair
といった主要なFlywayコマンドの役割と、具体的な使い方を習得できる。- コールバックやプレースホルダーといった応用的な機能を活用し、より高度なマイグレーション管理を行う方法がわかる。
- チーム開発におけるマイグレーションのコンフリクト回避や、順序が異なるマイグレーション(Out-of-Order)への対処法など、実践的なベストプラクティスを学べる。
第1章: Flywayとは? – データベースマイグレーションの重要性
ソフトウェア開発、特に複数人でのチーム開発において、アプリケーションのソースコードはGitなどのバージョン管理システムで管理するのが当たり前になっています。では、データベースのスキーマ(テーブル構造やインデックスなど)やデータはどうでしょうか?手動でSQLを実行したり、その場の思いつきで変更したりすると、「誰が」「いつ」「なぜ」その変更を行ったのかが追跡できなくなり、環境ごとの差異やデプロイ時のエラーといった深刻な問題を引き起こす原因となります。
この「データベースの変更履歴をバージョン管理し、安全かつ自動的に適用していく仕組み」をデータベースマイグレーションと呼びます。
Flywayの登場
Flywayは、このデータベースマイグレーションをシンプルかつ強力に支援してくれるオープンソースのツールです。Javaで実装されており、Javaアプリケーションとの親和性が非常に高いのが特徴です。アプリケーションの起動時に自動でマイグレーションを実行できるため、デプロイプロセスに簡単に組み込めます。
Flywayの主なメリットは以下の通りです。
- バージョンの自動管理: どのSQLがどの順番で適用されたかを自動で追跡します。
- SQL中心のアプローチ: 開発者は使い慣れたSQLでマイグレーションスクリプトを作成できます。XMLなどの複雑な独自形式を覚える必要はありません。
- 信頼性の向上: マイグレーションプロセスを自動化することで、手作業によるミスを防ぎ、開発環境と本番環境の一貫性を保ちます。
- 簡単なセットアップ: Spring Bootなどのモダンなフレームワークでは、非常に簡単な設定で導入できます。
FlywayはOracle, PostgreSQL, MySQL, SQL Server, H2など、非常に多くのデータベースをサポートしています。
第2章: Flywayのセットアップと基本設定 (Spring Boot編)
ここでは、最も一般的なユースケースであるSpring BootプロジェクトにFlywayを導入する方法を解説します。
1. 依存関係の追加
まず、プロジェクトのビルドファイルにFlywayの依存関係を追加します。Spring Bootを利用している場合、`spring-boot-starter-data-jpa`などのDB関連のStarterを追加すると、多くの場合`flyway-core`も含まれていますが、明示的に追加するのが確実です。
Maven (`pom.xml`) の場合:
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId>
</dependency>
<!-- 使用するデータベースに応じたJDBCドライバも必要です -->
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope>
</dependency>
Gradle (`build.gradle`) の場合:
implementation 'org.flywaydb:flyway-core'
// 使用するデータベースに応じたJDBCドライバも必要です
runtimeOnly 'org.postgresql:postgresql'
2. 基本設定
Spring Bootでは、application.properties
またはapplication.yml
に設定を記述するだけでFlywayが有効になります。
`application.properties` の場合:
# --- Database Connection ---
spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.username=user
spring.datasource.password=password
# --- Flyway Configuration ---
# Flywayを有効にする (デフォルトはfalseなので明示的にtrueにする)
spring.flyway.enabled=true
# マイグレーションファイルが格納されている場所を指定する (デフォルトは classpath:db/migration)
# spring.flyway.locations=classpath:db/migration
# アプリケーション起動時に、flyway_schema_historyテーブルがない場合に自動で作成し、
# baseline(基準)バージョンを適用する設定。既存DBへの導入に便利。
spring.flyway.baseline-on-migrate=true
`application.yml` の場合:
spring: datasource: url: jdbc:postgresql://localhost:5432/mydatabase username: user password: password flyway: enabled: true baseline-on-migrate: true # locations: classpath:db/migration
Flywayの動作の仕組み: `flyway_schema_history`テーブル
Flywayが初めてデータベースに接続し、マイグレーションを実行しようとすると、`flyway_schema_history`という特別な管理テーブルをデータベース内に作成します。このテーブルには、適用されたマイグレーションのバージョン、説明、実行日、成否などの情報が記録されます。
アプリケーションが起動するたびに、Flywayは以下の処理を行います。
- 設定された`locations`(デフォルトは`src/main/resources/db/migration`)にあるマイグレーションファイルをスキャンします。
- `flyway_schema_history`テーブルの内容と照合します。
- まだ適用されていない(`flyway_schema_history`に記録されていない)新しいバージョンのマイグレーションファイルを見つけると、バージョン番号の昇順で実行します。
- 実行が成功すると、その結果を`flyway_schema_history`に記録します。
この仕組みにより、常にデータベースの状態が最新に保たれるのです。
第3章: マイグレーションファイルの作成と命名規則
Flywayの核となるのがマイグレーションファイルです。Flywayは、ファイルの命名規則に基づいてその種類と実行順序を判断します。
バージョニングされたマイグレーション (Versioned Migrations)
最も一般的に使用されるマイグレーションで、一度だけ実行されることを意図しています。テーブルの作成(CREATE TABLE)、カラムの追加(ALTER TABLE ADD COLUMN)など、スキーマ構造を変更する処理に使用します。
命名規則: V<バージョン>__<説明>.sql
- Prefix:
V
で始まる必要があります。 - Version: バージョン番号。ドット(
.
)やアンダースコア(_
)で区切られた数字で構成されます。Flywayはアンダースコアをドットに変換して解釈します。例: `1`, `1.1`, `2025.07.12.1`, `1_1`(1.1として解釈) - Separator: バージョンと説明を区切るための、2つのアンダースコア (
__
)。 - Description: マイグレーションの内容を示す説明。アンダースコア(
_
)はスペースに置き換えられます。 - Suffix:
.sql
良い例:
V1__Create_user_table.sql
V1.1__Add_email_column_to_user_table.sql
V20250712103000__Create_product_master.sql
(タイムスタンプベースのバージョン)
リピータブルマイグレーション (Repeatable Migrations)
リピータブルマイグレーションはバージョンを持たず、その内容(チェックサム)が変更されるたびに再適用されます。ビュー(VIEW)の再作成、ストアドプロシージャや関数の更新、参照データの再投入など、冪等性(べきとうせい:何度実行しても結果が同じになること)を保てる処理に使用すると非常に便利です。
リピータブルマイグレーションは、全てのバージョニングされたマイグレーションが適用された後に、ファイル名のアルファベット順で実行されます。
命名規則: R__<説明>.sql
- Prefix:
R
で始まる必要があります。 - Separator: 2つのアンダースコア(
__
)。 - Description: 説明。
- Suffix:
.sql
良い例:
R__Create_or_update_user_summary_view.sql
R__Insert_master_data.sql
リピータブルマイグレーションを実装する際は、CREATE OR REPLACE VIEW ...
や、一度データを削除してから挿入する(`TRUNCATE TABLE …; INSERT INTO …;`)など、何度実行しても問題ないようにSQLを記述する必要があります。
第4章: Flywayの主要コマンド徹底解説
Flywayには、データベースマイグレーションを管理するためのいくつかの重要なコマンドがあります。Spring Boot環境では、アプリケーション起動時に自動で`migrate`が実行されますが、開発中にはMaven/Gradleプラグインやコマンドラインツールを使ってこれらのコマンドを意図的に実行することが役立ちます。
migrate
最も基本的で最もよく使われるコマンドです。データベースのスキーマを最新バージョンに移行します。具体的には、`flyway_schema_history`テーブルにまだ記録されていないPending状態のマイグレーションをバージョン順に適用します。
# Mavenの場合
mvn flyway:migrate
# Gradleの場合
./gradlew flywayMigrate
info
全てのマイグレーションの状態を詳細に表示します。どのバージョンまで適用済みか、どのマイグレーションがPending(保留中)状態か、あるいは失敗(Failed)しているかなどを確認できます。開発中に現在のデータベースの状態を把握するために非常に有用です。
# Mavenの場合
mvn flyway:info
# Gradleの場合
./gradlew flywayInfo
出力例:
Category | Version | Description | Type | Installed On | State |
---|---|---|---|---|---|
Versioned | 1 | Create user table | SQL | 2025-07-12 10:00:00 | Success |
Versioned | 1.1 | Add email column | SQL | 2025-07-12 10:00:01 | Success |
Versioned | 2 | Create product table | SQL | Pending | |
Repeatable | User summary view | SQL | 2025-07-12 10:00:02 | Success |
validate
マイグレーションファイルと`flyway_schema_history`テーブルの整合性を検証します。以下の問題を検出します。
- 適用済みのマイグレーションファイルのチェックサムが変更されている (ファイルが書き換えられた)。
- `flyway_schema_history`には記録されているが、マイグレーションファイルが存在しない。
CI/CDパイプラインにこのコマンドを組み込むことで、誤った変更がデプロイされるのを防ぐことができます。
# Mavenの場合
mvn flyway:validate
# Gradleの場合
./gradlew flywayValidate
検証に失敗した場合、エラーメッセージが表示され、問題が解決されるまで`migrate`は実行できなくなります。
clean
【警告】非常に危険なコマンドです。 設定されたスキーマ内の全てのオブジェクト(テーブル、ビューなど)を完全に削除します。データベースを初期状態に戻したい開発環境やテスト環境でのみ使用してください。本番環境では絶対に実行してはいけません。 デフォルトでは`flyway.cleanDisabled`が`true`になっており、誤操作を防いでいます。実行するには明示的に無効化する必要があります。
# Mavenの場合 (-Dflyway.cleanDisabled=false を付ける必要がある)
mvn flyway:clean -Dflyway.cleanDisabled=false
# Gradleの場合
./gradlew flywayClean -Pflyway.cleanDisabled=false
baseline
すでにテーブルやデータが存在する既存のデータベースにFlywayを導入する場合に使用します。このコマンドは、指定したバージョンで`flyway_schema_history`テーブルを初期化します。
例えば、手動でバージョン1.0相当まで構築済みのデータベースにFlywayを導入する場合、`flyway.baselineVersion=1.0`と設定して`baseline`コマンドを実行します。これにより、Flywayはバージョン1.0までのマイグレーションは「適用済み」とみなし、それ以降のバージョンからマイグレーションを開始します。
# Mavenの場合
mvn flyway:baseline -Dflyway.baselineVersion=1.0 -Dflyway.baselineDescription="Initial baseline"
# Gradleの場合
./gradlew flywayBaseline -Pflyway.baselineVersion=1.0 -Pflyway.baselineDescription="Initial baseline"
`spring.flyway.baseline-on-migrate=true`を設定しておくと、`migrate`実行時に`flyway_schema_history`テーブルが存在しない場合に自動で`baseline`が実行されるため便利です。
repair
`flyway_schema_history`テーブルの問題を修復するためのコマンドです。主に2つの目的で使われます。
- 失敗したマイグレーションエントリの削除: マイグレーションが途中で失敗すると、`flyway_schema_history`に`Failed`状態のレコードが残ります。この状態では次のマイグレーションに進めません。失敗の原因となったSQLを手動で修正・ロールバックした後、`repair`を実行してこの失敗レコードを削除し、再度の`migrate`を可能にします。
- チェックサムの再調整: 何らかの理由で適用済みのマイグレーションファイルのチェックサムが変更され、`validate`でエラーになった場合、`repair`を実行すると現在のファイル内容に合わせて`flyway_schema_history`テーブルのチェックサムを更新します。ただし、これは意図しない変更を正当化してしまうリスクがあるため、慎重に使用する必要があります。
# Mavenの場合
mvn flyway:repair
# Gradleの場合
./gradlew flywayRepair
第5章: 応用的な機能とベストプラクティス
Flywayの基本をマスターしたら、さらに高度な機能を使ってマイグレーションをより柔軟かつ堅牢に管理しましょう。
コールバック (Callbacks)
Flywayはマイグレーションのライフサイクルの特定のタイミングで、追加のロジックをフックする「コールバック」機能を提供します。これにより、全てのマイグレーションの前後や、個々のマイグレーションの前後などで決まった処理を実行できます。
コールバックには主にSQLベースとJavaベースの2種類があります。
SQLコールバック:
マイグレーションファイルと同じ場所に、特定の命名規則に従ったSQLファイルを置くだけで有効になります。
beforeMigrate.sql
: `migrate`コマンドが開始される前に実行されます。afterMigrate.sql
: `migrate`コマンドが成功した後に実行されます。beforeEachMigrate.sql
: 各バージョニング/リピータブルマイグレーションが実行される直前に実行されます。afterEachMigrate.sql
: 各バージョニング/リピータブルマイグレーションが成功した直後に実行されます。
例えば、afterMigrate.sql
を使って、マイグレーション後に必ず更新が必要なマテリアライズドビューをリフレッシュする、といった使い方が考えられます。
Javaコールバック:
より複雑なロジックが必要な場合(例:外部APIの呼び出し、キャッシュのクリア)、Javaで`org.flywaydb.core.api.callback.Callback`インターフェースを実装し、SpringのBeanとして登録することで、コールバックを実装できます。
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.Context;
import org.flywaydb.core.api.callback.Event;
import org.springframework.stereotype.Component;
@Component
public class FlywayCallbackLogger implements Callback { @Override public boolean supports(Event event, Context context) { // すべてのイベントをサポートする return true; } @Override public boolean canHandleInTransaction(Event event, Context context) { // トランザクション内で実行できるか return true; } @Override public void handle(Event event, Context context) { // イベント発生時に実行したいロジック System.out.println("Flyway Callback Event: " + event.getId()); } @Override public String getCallbackName() { return "LoggerCallback"; }
}
プレースホルダー (Placeholders)
SQLマイグレーションファイル内で変数を使い、環境ごとに異なる値を埋め込みたい場合があります。例えば、スキーマ名や特定のロール名などを開発環境と本番環境で変えたいケースです。この要求に応えるのがプレースホルダー機能です。
application.properties
でプレースホルダーを定義します。
# Define placeholders
spring.flyway.placeholders.read-only-user=app_readonly
spring.flyway.placeholders.target-schema=public
そして、SQLファイル内で `${…}` という構文を使って参照します。
例: V3__Grant_select_privilege.sql
-- 読み取り専用ユーザーにSELECT権限を付与
GRANT SELECT ON ALL TABLES IN SCHEMA ${target-schema} TO ${read-only-user};
`migrate`実行時、Flywayはこれらのプレースホルダーを設定ファイルの値に置き換えてからSQLを実行します。
チーム開発でのベストプラクティス
バージョニング戦略
複数人で同時に開発を進めていると、マイグレーションのバージョン番号が衝突する可能性があります。`V2__…`というファイルを2人の開発者が同時に作成してしまうようなケースです。これを避けるため、以下のような戦略が有効です。
- タイムスタンプベースのバージョニング: `V20250712103000__…`のように、バージョン番号に年月日時分秒を使うことで、一意性をほぼ保証できます。
順序が異なるマイグレーション (Out-of-Order Migrations)
Gitでブランチをマージする順番によっては、より古いバージョン番号を持つマイグレーションが後からmainブランチに入ってくることがあります。例えば、`V2`が適用済みの環境に、後から`V1.5`を含むブランチがマージされた場合です。
デフォルトでは、Flywayはこの`V1.5`を「順序が違う(Out of Order)」とみなし、無視してエラーを発生させます。しかし、これを許容したい場合もあります。その場合は、以下の設定を追加します。
# application.properties
spring.flyway.out-of-order=true
この設定を有効にすると、Flywayは順序が異なるマイグレーションも適用してくれるようになります。ただし、マイグレーションスクリプトが互いに依存しないように設計されていることが前提となるため、注意が必要です。
ホットフィックスの適用
本番環境で緊急の修正が必要になった場合、新しいバージョンのマイグレーションファイルを作成して対応します。例えば、現在の最新が`V5`であれば、`V5.1__Hotfix_for_issue_123.sql`のようなファイルを作成して適用します。Flywayの仕組みに従うことで、修正履歴もバージョン管理され、安全に適用できます。
まとめ
Flywayは、Java開発におけるデータベースマイグレーションの複雑さとリスクを劇的に軽減してくれる強力なツールです。SQL中心のシンプルなアプローチでありながら、コマンド、コールバック、プレースホルダーなどの機能を通じて、開発から本番までのあらゆるシナリオに柔軟に対応できます。
この記事で解説した基本概念から応用的なテクニックまでをマスターすることで、あなたはデータベースの変更を恐れることなく、自信を持ってアプリケーション開発を進めることができるようになるでしょう。データベーススキーマもソースコードの一部として扱い、一貫性のある信頼性の高いシステムを構築するために、ぜひFlywayを導入してみてください。