【Flyway入門】手を動かしてマスター!Spring Boot + Flywayで作る、変更に強いデータベースの育て方

「またDBスキーマで失敗…」から卒業しませんか?

「本番環境でデプロイしたら、DBスキーマが違うせいでエラーが発生…」
「複数人で開発していると、いつの間にかスキーマのバージョンがバラバラに…」

開発現場で、このような“見えない地雷”に遭遇した経験はありませんか? データベーススキーマの変更は避けられませんが、その管理は非常にデリケートな作業です。

この記事では、データベースマイグレーションツール「Flyway」を、Spring Boot環境で動かしながら学ぶための「入門ガイド」をお届けします。

この記事を読み終える頃には、あなたはFlywayという強力な武器を手にし、安全で効率的なデータベース管理の第一歩を踏み出しているはずです。

さあ、一緒にはじめていきましょう!


対象読者

この記事は、以下のような方を対象としています。

  • Spring Bootの基本的な開発経験がある方
  • データベースのスキーマ管理に課題を感じている、または興味がある開発者
  • 「Flyway」というツールを初めて学ぶ、または導入を検討している方
  • 手動でのSQL実行によるヒューマンエラーを防ぎたいと考えている方
  • チーム開発におけるデータベース変更の管理方法を改善したい方

目次


本記事で学ぶこと

  • Spring BootプロジェクトにFlywayを導入する基本的な方法
  • Flywayを使ったデータベースマイグレーションの実行手順
  • バージョン管理されたSQLスクリプトの作成と管理の基本
  • flyway_schema_historyテーブルの役割の理解

1. 開発環境の準備

まずは、Flywayを動かすための舞台を整えましょう。今回は、手軽に試せるように、インメモリデータベースであるH2 Databaseを利用しますが、もちろんFlywayは様々なデータベースに対応しています。


1.1. Spring Bootプロジェクトの作成

Spring Initializr(https://start.spring.io/)を使って、新しいSpring Bootプロジェクトを作成します。以下の依存関係を追加してください。

  • Spring Web
  • H2 Database
  • Flyway Migration
  • Spring Data JPA (任意)
  • Lombok (任意)
新しいSpring Bootプロジェクトを作成

Spring Bootの開発環境構築については、以下の記事で詳しく解説していますので、是非ご覧ください。


1.2. データベースのセットアップ

application.propertiesまたはapplication.ymlに、データベースへの接続設定と、Flywayを有効にするための設定を記述します。


H2 Database (インメモリDB)

まずは手軽に試せるH2 Databaseの設定です。

application.properties:

# H2 Database
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# Flyway
spring.flyway.enabled=true

PostgreSQL の場合

実運用でよく利用されるPostgreSQLへの接続例です。localhostの部分はデータベースサーバーのアドレスやホスト名に置き換えてください。

application.properties:

# PostgreSQL Database
spring.datasource.url=jdbc:postgresql://localhost:5432/your_database_name
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=org.postgresql.Driver

# JPA/Hibernate (Flywayと併用する場合の推奨設定)
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Flywayがスキーマ管理を行うため、HibernateのDDL自動生成は無効または検証モードに
spring.jpa.hibernate.ddl-auto=validate # または none

# Flyway
spring.flyway.enabled=true

MySQL の場合

こちらも広く利用されているMySQLへの接続例です。タイムゾーン設定 (serverTimezone=UTC) はMySQLのバージョンによっては必須です。

application.properties:

# MySQL Database
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA/Hibernate (Flywayと併用する場合の推奨設定)
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect # MySQLのバージョンに合わせて調整
# Flywayがスキーマ管理を行うため、HibernateのDDL自動生成は無効または検証モードに
spring.jpa.hibernate.ddl-auto=validate # または none

# Flyway
spring.flyway.enabled=true

【重要】 spring.jpa.hibernate.ddl-auto の設定について:

FlywayとJPA/Hibernateを連携させる際は、スキーマ管理の責任をFlywayに集約させることが重要です。application.propertiesには以下のような設定が推奨されます。

# --- FlywayとJPA/Hibernateを併用する際の推奨設定 ---

# Flyway
spring.flyway.enabled=true

# JPA/Hibernate
# スキーマ管理はFlywayに一任するため、HibernateのDDL自動生成は
# `validate`(検証)モードまたは`none`(無効)に設定します。
spring.jpa.hibernate.ddl-auto=validate

Spring BootアプリケーションでSpring Data JPA(Hibernate)を使用する場合、このspring.jpa.hibernate.ddl-autoというプロパティがデータベーススキーマの自動生成を制御します。

しかし、Flywayを使用する際は、このプロパティをvalidateまたはnoneに設定することを強く推奨します。

  • none: DDLの自動生成を完全に無効にします。スキーマの変更はすべてFlywayのマイグレーションスクリプトによって行われます。
  • validate: アプリケーション起動時に、現在のデータベーススキーマがエンティティマッピングと一致するかどうかを検証します。不一致があればエラーをスローし、問題の早期発見に役立ちます。

createupdateなどの設定は、Hibernateが自動的にスキーマを変更しようとするため、Flywayと競合し、予期せぬ問題を引き起こす可能性があります。スキーマ変更はFlywayに一元化し、Hibernateはスキーマの検証のみを行うようにしましょう。

以下に、FlywayとHibernate(ddl-auto: validate)が連携する際の起動フローを図で示します。

FlywayとHibernate(ddl-auto: validate)が連携する際の起動フロー

この図が示すように、Flywayが責任を持ってスキーマを構築・変更し、Hibernateはその結果がアプリケーションのエンティティ定義と一致しているかを検証する、という役割分担が実現できます。

これで、Spring Bootアプリケーションは起動時に指定されたデータベースに接続し、Flywayによるマイグレーションを自動的に実行するようになります。


2. Flywayの依存関係を追加

Spring InitializrでFlyway Migrationを選択していれば、すでにpom.xml(Maven)またはbuild.gradle(Gradle)に必要な依存関係が追加されています。

pom.xml (Maven):

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

build.gradle (Gradle):

implementation 'org.flywaydb:flyway-core'

3. Flywayの基本設定

Spring Bootは、application.properties(またはyml)に記述された設定を自動で読み込み、Flywayを構成してくれます。


3.1. 「設定より規約」とスクリプトの配置場所

Flywayを理解する上で非常に重要なのが、「設定より規約(Convention over Configuration)」という設計思想です。これは、「開発者が決まりきった設定を毎回書く手間を省き、生産性を高めるために、賢明なデフォルト値(規約)を提供する」という考え方です。

Flywayはこの思想を全面的に採用しており、その最も分かりやすい例が、マイグレーションスクリプトを配置する場所です。


デフォルトの規約

Flywayは、特に設定をしない限り、デフォルトでsrc/main/resources/db/migrationというディレクトリにあるマイグレーションスクリプトを探しに行きます。

まずは、この規約に従ってディレクトリを作成しましょう。

src
└── main
    └── resources
        └── db
            └── migration

たったこれだけです。application.propertiesにスクリプトの場所を記述する必要はありません。この規約に従うだけで、Flywayは自動的にスクリプトを認識してくれます。


規約に従うメリット

この「規約」に従うことには、多くのメリットがあります。

  • 生産性の向上: 面倒な設定ファイル記述から解放され、すぐに本質的な作業(SQLスクリプトの作成)に取り掛かれます。
  • 可読性と保守性の向上: Flywayを使っているプロジェクトなら、誰が見ても「ああ、あそこにSQLファイルがあるな」と一目でわかります。
  • チーム開発の円滑化: 全員が同じルールで作業するため、コードの一貫性が保たれ、属人化を防ぎます。

後ほど詳しく解説するスクリプトの命名規則 (V1__..., V2__...) も、Flywayが実行順序を判断するための重要な「規約」の一つです。


【補足】規約は変更も可能

もちろん、規約は絶対ではありません。プロジェクトの事情でどうしてもスクリプトの場所を変えたい場合、Flywayは設定によって規約を上書き(オーバーライド)する柔軟性も備えています。

例えば、application.propertiesに以下のように記述すれば、スクリプトの場所をdb/changelogに変更できます。

# スクリプトの場所をデフォルトから変更する場合
spring.flyway.locations=classpath:db/changelog

しかし、特別な理由がない限りは、デフォルトの規約に従うことを強く推奨します。その方が、Flywayの恩恵を最大限に受けることができるからです。


4. 初めてのマイグレーションスクリプト作成

いよいよ、最初のマイグレーションスクリプトを作成します。


4.1. 命名規則とSQLの書き方

Flywayのマイグレーションスクリプトは、厳格な命名規則に従う必要があります。

V<バージョン>__<説明>.sql

  • V: Versioned Migration(バージョン管理されるマイグレーション)であることを示す接頭辞。
  • <バージョン>: 1, 1.1, 202512270900のようなバージョン番号。アンダースコアで区切ることもできます。
  • __: ダブルアンダースコアでバージョンと説明を区切ります。
  • <説明>: マイグレーションの内容を簡潔に記述します。
  • .sql: SQLスクリプトであることを示す拡張子。

今回は、usersテーブルを作成するスクリプトを作成してみましょう。ファイル名はV1__create_users_table.sqlとします。


4.2. テーブル作成の例

src/main/resources/db/migration/V1__create_users_table.sql

-- usersテーブルを作成
CREATE TABLE users (
    id BIGINT NOT NULL AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

このSQLファイルを作成し、保存してください。

もちろん、最初のテーブル作成後も、スキーマは進化し続けます。

次に、インデックスを追加するマイグレーションと、新しいカラムを追加するマイグレーションの例を見てみましょう。

これにより、マイグレーションファイルがどのように積み重なっていくかを具体的に理解できます。


4.3. インデックス追加の例

src/main/resources/db/migration/V2__add_index_to_users_email.sql

-- usersテーブルのemailカラムにユニークインデックスを追加
-- これにより、emailの重複を防ぎ、検索速度を向上させます
CREATE UNIQUE INDEX uix_users_email ON users (email);

4.4. カラム追加の例

src/main/resources/db/migration/V3__alter_users_add_column_age.sql

-- usersテーブルにageカラムを追加
ALTER TABLE users ADD COLUMN age INT;

このように、V1, V2, V3…とバージョン番号をインクリメントしながらスクリプトファイルを追加していくことで、データベーススキーマの変更履歴がコードとして正確に管理されます。


5. Flywayの実行と確認

5.1. Spring Bootアプリケーション起動時の自動実行

Spring Bootアプリケーションを起動すると、Flywayが自動的に実行され、V1__create_users_table.sqlスクリプトが適用されます。

コンソールログに以下のようなFlywayの実行ログが出力されるはずです。

...
2026-01-08T23:08:26.989+09:00  INFO 41601 --- [flyway_demo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "1 - create users table"
2026-01-08T23:08:26.996+09:00  INFO 41601 --- [flyway_demo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "2 - add index to users email"
2026-01-08T23:08:27.000+09:00  INFO 41601 --- [flyway_demo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version "3 - alter users add column age"
...

5.2. flyway_schema_historyテーブルの確認

Flywayは、どのマイグレーションがいつ実行されたかを記録するためにflyway_schema_historyという特別なテーブルをデータベース内に作成します。

H2コンソール(http://localhost:8080/h2-console)にアクセスし、flyway_schema_historyテーブルの中身を確認してみましょう。

V1__create_users_table.sqlが実行された記録が残っているはずです。

Flywayは、どのマイグレーションがいつ実行されたかを記録するためにflyway_schema_historyという特別なテーブルをデータベース内に作成

まとめ

お疲れ様でした! この入門記事を通じて、あなたはFlywayの基本的な概念と、Spring Bootプロジェクトで実際にマイグレーションを実行するまでの一連の流れを体験しました。

  • マイグレーションはSQLファイルで管理され、
  • V1__..., V2__... という命名規則でバージョン管理され、
  • アプリケーション起動時に自動で適用される

というFlywayの強力かつシンプルな仕組みを実感いただけたかと思います。
もう手動でのSQL実行や、環境ごとのスキーマ差異に悩まされることはありません。


免責事項

本記事に掲載されている情報は、記事作成時点での情報に基づいています。ソフトウェアのバージョンアップ等により、コマンドや手順、UIが変更される可能性があります。本記事の情報を利用したことによって生じたいかなる損害についても、筆者は一切の責任を負いませんので、あらかじめご了承ください。作業はご自身の判断と責任において行ってください。


SNSでもご購読できます。

コメントを残す

*