Tech Blog

Flyway でスキーマ migration を段階的に育てていく運用方法

Flyway Spring Boot PostgreSQL Java

はじめに

「Flywayを入れたけど、どう使えばいいのかわからない」

最初にFlywayを触ったとき、そんな状態でした。
公式ドキュメントを読むと V1__create_table.sql から始まる例が載っていますが、

  • 既存のDB(dvdrental)があるとき、どう始めるか
  • 開発中にスキーマを追加・修正するとき、どの単位でファイルを作るか
  • 本番とローカルで状態が合わなくなったとき、どう対処するか

このような実運用上の疑問が解決しにくかったです。

この記事は、実際のプロジェクトでFlywayをどう使っているかの記録です。


Flywayとは

DBスキーマの変更履歴をSQLファイルで管理するツールです。

resources/db/migration/
  V1__initial_schema.sql
  V2__add_customer_app_schema.sql
  V3__add_taste_tags_to_film.sql
  • アプリ起動時に未適用のSQLを順番に実行する
  • 適用済みのSQLは flyway_schema_history テーブルに記録される
  • 一度適用したSQLは変更不可(変更するなら新しいSQLを追加)

セットアップ

<!-- pom.xml -->
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
</dependency>
# application.yml
spring:
  flyway:
    enabled: true
    locations: classpath:db/migration
    baseline-on-migrate: true  # 既存DBに適用する場合に必要
    baseline-version: 0

既存DBへの適用(dvdrental のケース)

dvdrental は既存のサンプルDBです。テーブルが既に存在する状態でFlywayを追加しました。

baseline-on-migrate の重要性

spring:
  flyway:
    baseline-on-migrate: true
    baseline-version: 0

既存DBに初めてFlywayを適用するとき、このオプションがないと
「テーブルが既に存在するのにV1のSQLを実行しようとして失敗する」問題が起きます。

baseline-on-migrate: true を設定すると、Flywayは「V0以前の状態はこのDBが初期状態」として扱い、
V1以降のSQLだけを適用します。

初期SQLの書き方

既存テーブルはFlywayの管理外なので、V1は「今ある状態からの差分」だけを書けばよいです。

-- V1__baseline.sql(空ファイルまたはコメントのみ)
-- dvdrental の既存テーブルはFlywayの管理外
-- V2以降でcustomer_app スキーマへの追加を管理する

実際に使ったmigrationファイル

V2:customer_app スキーマの作成

-- V2__create_customer_app_schema.sql
CREATE SCHEMA IF NOT EXISTS customer_app;

CREATE TABLE customer_app.app_user (
    user_id     BIGSERIAL PRIMARY KEY,
    email       VARCHAR(255) NOT NULL UNIQUE,
    password    VARCHAR(255) NOT NULL,
    full_name   VARCHAR(255),
    created_at  TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

V3:映画タグカラムの追加

-- V3__add_taste_tags_to_film.sql
ALTER TABLE film ADD COLUMN IF NOT EXISTS taste_tags TEXT[];

COMMENT ON COLUMN film.taste_tags IS 'LLMで自動生成した雰囲気タグ';

V4:カートテーブルの作成

-- V4__create_cart_tables.sql
CREATE TABLE customer_app.cart (
    cart_id     BIGSERIAL PRIMARY KEY,
    user_id     BIGINT NOT NULL REFERENCES customer_app.app_user(user_id),
    created_at  TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE customer_app.cart_item (
    cart_item_id    BIGSERIAL PRIMARY KEY,
    cart_id         BIGINT NOT NULL REFERENCES customer_app.cart(cart_id),
    film_id         INTEGER NOT NULL REFERENCES film(film_id),
    added_at        TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

ファイル命名の規則

V{バージョン}__{説明}.sql
  • バージョンは整数またはドット区切り(V1, V1.1, V2 など)
  • アンダースコアが2つ(__
  • 説明はスネークケース
V1__baseline.sql
V2__create_customer_app_schema.sql
V3__add_taste_tags_to_film.sql
V3_1__add_index_to_film_taste_tags.sql  ← V3の後に追加したい場合

よくある失敗と対処法

① 適用済みSQLを誤修正してしまった

ERROR: Detected failed migration to version 3
FlywayException: Validate failed: 
Detected applied migration not resolved locally: 3

Flywayは適用済みSQLのチェックサムを記録しています。
変更すると不一致エラーが出ます。

対処法: 絶対に変更しない。修正が必要なら新しいバージョンのSQLを作る。

② ローカルと本番でFlywayの状態がずれた

開発中にV3を適用してから、V2のSQLを直したくなることがあります。
その場合は flyway_schema_history テーブルで状態を確認します。

SELECT * FROM flyway_schema_history ORDER BY installed_rank;

③ テストでFlywayを使いたくない

# application-test.yml
spring:
  flyway:
    enabled: false
  jpa:
    hibernate:
      ddl-auto: create-drop  # テスト用にHibernateでスキーマを管理

開発フロー

1. 新機能のDBスキーマが必要になる

2. V{次の番号}__{説明}.sql を作成

3. ローカルでアプリ起動 → Flywayが自動適用

4. 動作確認

5. コミット → 本番デプロイ時にも自動適用

「スキーマの変更 = SQLファイルの追加」という運用になるので、
DBの変更がGitの差分として残り、レビューやロールバックがしやすくなります。


まとめ

ポイント詳細
既存DBへの適用baseline-on-migrate: true で初期状態をセット
ファイル命名V{バージョン}__{説明}.sql(Vは大文字、__は2つ)
一度適用したSQLは変更禁止修正は新しいバージョンで
追加の単位テーブル作成・カラム追加・インデックス追加など操作ごとにファイルを分ける

Flywayを使うとDBのスキーマ変更が「コードの変更」と同じように扱えるようになります。
「本番のDBがどうなっているか」を確認するためにDBに直接ログインする頻度が大幅に減ります。


このシリーズの記事マップ

dvdrental 管理アプリと対になるエンドユーザー向けDVDレンタルアプリを作っている話 — Vue 3 + Spring Boot の全体構成と記事マップ

気軽にメッセージください

技術相談・ご感想・ご質問があればメッセージをお願いします。