Spring BootとFlywayでDB変更を管理する|マイグレーションの基本

Spring BootとFlywayでDB変更を管理する|マイグレーションの基本

開発環境では動くのに、テスト環境や本番環境ではテーブルやカラムが足りず、アプリケーションが起動しない。こうした差を減らすには、データベースの変更もアプリケーションのソースコードと一緒に管理する必要があります。

Flywayは、SQLなどで記述した変更を順番に適用し、適用履歴を記録するデータベースマイグレーションツールです。Spring Bootでは依存関係と設定を整えると、アプリケーション起動時にFlywayを実行できます。この記事では、導入の基本から既存DBへの適用、検証、失敗時の確認までを整理します。

目次

Flywayで管理するDBスキーマ変更の範囲

テーブル作成やカラム追加、インデックス変更などをSQLファイルとして残し、どの変更をどの順番で適用したかを管理するのがFlywayの基本です。変更ファイルは通常、アプリケーションのリポジトリでコードと一緒にレビュー・バージョン管理します。開発者ごとに手作業でSQLを実行する運用と比べ、環境へ適用する変更を共有しやすくなります。

Flywayは、実データベースの全オブジェクトを毎回読み取って理想状態との差分SQLを自動生成する仕組みとは異なります。チームが用意したマイグレーションを順に解決・適用し、履歴テーブルで状態を記録します。そのため、SQLの内容、順序、接続先、既存環境の状態を確認する責任は開発・運用側に残ります。

versioned migrationと適用履歴の役割

バージョン付きマイグレーションは、バージョンと説明をファイル名に含め、対象DBに一度だけ適用する変更です。Flywayは適用したバージョンや実行結果などをflyway_schema_historyという履歴テーブルに記録します。SQLファイルのチェックサムも保存されるため、適用済みファイルが後から書き換えられた場合に差異を検出できます。

「どのDBにも同じファイルを適用した」ことと、「各DBが現在同じ状態である」ことは同じではありません。手作業の変更、環境ごとのデータ、適用失敗、古い履歴などがあると差が生じます。マイグレーション履歴に加え、対象スキーマ、アプリのバージョン、バックアップや復旧手順も確認できる運用にしておきます。

Spring BootでFlywayを使うための設定

導入時は、Spring Boot、Flyway、Java、データベース、JDBCドライバの対応関係を確認します。必要な依存関係はSpring Bootの世代やFlywayのバージョン、DB製品によって異なります。たとえばSpring Boot 3.5の公式ガイドでは、MySQLなどではFlyway本体に加えてデータベース用モジュールが必要とされています。一方、別世代ではスターター構成が案内されることもあるため、古い記事の依存関係をそのままコピーせず、採用中のバージョンの公式資料に合わせてください。

MySQLを使うプロジェクトでは、依存関係の例としてorg.flywaydb:flyway-coreとorg.flywaydb:flyway-mysqlが案内されています。これはSpring Boot 3.5系の説明を基にした例です。実際のGradleやMavenの記述、各バージョンはプロジェクトの依存関係管理に合わせて決めます。Flyway Teams限定機能など、エディションによる違いも利用前に確認します。

Spring Bootの標準的なマイグレーションファイルの場所はclasspath:db/migrationです。別の場所に置く場合はspring.flyway.locationsで指定します。以下は配置先を明示する最小の設定例です。認証情報は設定ファイルへ直接書かず、環境変数やシークレット管理の仕組みから渡してください。

spring:
  flyway:
    locations: "classpath:db/migration"

Spring BootはFlywayがクラスパス上にある場合などの条件に応じて自動設定を行い、起動処理の中でマイグレーションを実行します。専用の接続先を設定する場合はspring.flyway.url、spring.flyway.userなどを使えますが、通常はアプリケーションのDataSourceを利用する構成が基本です。設定値の既定値や条件は、利用しているSpring Bootの公式プロパティ一覧で確認します。

ほかのスキーマ初期化処理との重複を避ける

Flywayを導入したら、schema.sqlやdata.sql、Hibernateのddl-auto=createなど、同じスキーマを変更する別の仕組みが動いていないか確認します。複数の仕組みが同じテーブルを作成・変更すると、実行順の違いで起動に失敗したり、環境ごとに異なる状態になったりします。

Spring Bootの公式ガイドは、FlywayやLiquibaseのようなマイグレーションツールを使う場合、基本のSQL初期化スクリプトを同時にスキーマ作成へ使わないことを勧めています。Hibernateのスキーマ検証が必要な場合も、Flywayと役割を分け、たとえばFlywayが変更を適用し、Hibernateは想定スキーマとの整合性確認に使う、といった形を検討します。具体的な設定は使用中のSpring BootとORMの仕様に従ってください。

versioned migrationで変更を積み重ねる

バージョン付きSQLファイルは、一般にV<バージョン>__<説明>.sqlの形式で命名します。たとえば次の例では、最初のファイルでテーブルを作り、次のファイルでカラムを追加します。SQL構文やオンライン変更の可否は、対象のDB製品とバージョンに合わせて確認してください。

-- src/main/resources/db/migration/V1__create_customer.sql
CREATE TABLE customer (
  id BIGINT NOT NULL PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);

V1適用後に列を追加する場合は、別ファイルのV2として管理します。以下はstatus列を追加する例です。実際の列名・初期値・ロック時間などは対象DBと既存データを踏まえて確認してください。

-- src/main/resources/db/migration/V2__add_customer_status.sql
ALTER TABLE customer
  ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'active';

Flywayは未適用のバージョン付き変更をバージョン順に適用し、成功・失敗などの履歴を記録します。適用済みのV1ファイルへ後からテーブル定義を追記すると、保存済みチェックサムと合わずvalidateで問題になります。すでに共有環境へ適用した変更は原則として編集せず、修正が必要なら新しいバージョンのマイグレーションを追加して前へ進めます。

起動時の適用結果と再起動後の履歴を確認する

開発環境でアプリを起動しただけで完了とせず、ログに適用対象やエラーが出ていないか確認します。続けてflyway_schema_historyを参照し、想定したバージョンが成功として記録されているかを確認します。再起動時に同じバージョンが再実行されないことも、利用している環境で確かめます。

マイグレーションは通常、ソース変更と一緒にレビューします。変更SQLが既存データをどう扱うか、NULLや初期値が既存行に影響しないか、インデックス作成が大きな表でどの程度の時間やロックを伴うかを検討します。インデックス設計の一般的な観点は、MySQLインデックスの記事も参考になります。

適用済みファイルを変更できるか迷う場合は、適用先の環境と履歴を先に確認します。ローカルでしか使っていない変更と、共有の開発・検証・本番のいずれかに適用済みの変更では扱いが異なります。「まだ誰も使っていないはず」という想定でファイルを上書きするのではなく、チームと適用状況をそろえてから次の変更を作ります。

既存DBへ導入するときのbaselineの注意点

すでに稼働中のデータベースへFlywayを追加するときは、新規DBへ導入するときより慎重な確認が必要です。現在のテーブル定義、データ、各環境の差、すでに実行しているSQLを調べずに最初のマイグレーションを流すと、既存テーブルをもう一度作ろうとして失敗したり、想定と違う変更が適用されたりするおそれがあります。

baselineは、既存DBをFlywayで管理し始めるときの「管理開始時点」を履歴へ記録する仕組みです。baselineを実行しても、既存スキーマがリポジトリ内のSQLと完全一致することを自動的に証明したり、差分を修正したりするわけではありません。まず本番の複製やステージングなどでスキーマを比較し、どの状態を基準とするか決めます。

導入手順の一例は、現状把握、バックアップ確認、代表環境の複製、基準状態の合意、baseline設定、baseline後の新しい変更の適用、という順です。環境間でスキーマが揃っていない場合は、どの環境を正とするのかを先に決め、必要な差分を個別に解消します。状態が不明な本番DBへ、確認のためだけにbaselineを直接実行するのは避けます。

baseline-on-migrateを安易に有効化しない

baseline-on-migrateは、Flywayが対象としているスキーマが空ではなく、schema history tableがまだない状態でmigrateを実行したときに、自動でbaselineを呼び出す設定です。すでにFlywayの履歴テーブルがあるDBへ、baselineを重ねて実行する設定ではありません。判定対象は指定したスキーマ構成に依存し、空のスキーマに対応するbaseline migrationがある場合はそれを実行するケースもあるため、利用中のFlyway設定と公式資料を確認します。

自動化する場合は、どの環境で有効になるのか、baselineのバージョンは何か、既存DBの内容をどう照合したかを設定と運用手順に残します。まず明示的な手順で複製環境へ導入し、結果を確認したうえで自動化の必要性を判断する方法もあります。baselineの詳細はFlyway公式ガイドを参照してください。

baselineは既存スキーマの正しさを検査する機能ではありません。対象DBと基準バージョンを確認し、復旧方法を用意してから実施します。

validateとマイグレーション失敗時の考え方

flyway validateは、利用可能なマイグレーションと適用履歴を照合するコマンドです。名前・種類・チェックサムの違いや、履歴にあるのにファイルが見つからない状態などを検出します。適用済みSQLを誤って書き換えていないか、履歴が期待どおりかを調べる用途に使えます。

一方、validateが成功しても、DB上のすべてのテーブルやインデックスがファイルの定義と完全一致するとは限りません。手動DDLによるスキーマドリフト、想定外のデータ状態、アプリケーションが要求する性能などは、別途確認が必要です。必要に応じてDBの定義情報、デプロイ記録、アプリケーション側の確認を組み合わせます。

検証エラーとSQL適用中の失敗を切り分ける

エラーが出たら、まず接続先、Flywayの起動ログ、失敗したマイグレーション名、flyway_schema_historyの該当行、実際のテーブル定義とデータを照合します。エラーがファイルのチェックサム不一致なのか、SQL実行中の制約違反なのか、接続や権限の問題なのかによって対応が異なるため、ログだけを見て再実行する判断はしません。

チェックサム不一致が出た場合、適用済みのファイルを編集して辻褄を合わせるのではなく、まず誰がどの環境でファイルを変更したかを確認します。意図しない変更であれば元のファイルへ戻し、変更が必要なら追加のマイグレーションを検討します。Flywayのrepairは履歴テーブルの状態を修復するコマンドで、実行済みDDLやデータを元に戻す機能ではありません。原因と現在のDB状態を把握せずに使わないでください。

Springの@Transactionalで業務データの変更を戻せるケースと、DBスキーマ変更の挙動は分けて考えます。MySQL 8.4ではALTER TABLEやCREATE INDEXなど一部のDDLが暗黙のコミットを行います。DDL全体がアプリケーションのトランザクションで必ずロールバックできるとは限らず、エンジン、文、バージョンによっても条件は異なります。

失敗後の安全な進め方は、変更がどこまで反映されたかを調べ、バックアップや復旧計画と照らしてから決めます。必要なら、互換性を保つ追加のマイグレーションを作る、アプリケーションを前の互換バージョンへ戻す、計画した復旧手順を使うなどを検討します。「同じコマンドをもう一度実行すれば直る」とは限りません。

アプリケーション処理のトランザクション境界とロールバックの基本は、Spring Bootのトランザクション記事で扱っています。FlywayのDDL適用と同一の仕組みとして扱わず、DB製品ごとの仕様を確認してください。

Testcontainersで変更手順を確認する

マイグレーションのテストでは、H2など別製品のインメモリDBだけでなく、本番と同じ種類のデータベースでSQLを確認することが重要です。方言や型、DDLの挙動はDB製品によって違うため、開発でMySQLを使うならMySQLのコンテナを用意し、対象のドライバとFlyway設定を使う構成を検討します。

テストでは、空のDBへ全マイグレーションを適用するケースに加え、前のバージョンまで適用済みのDBから新しい変更を適用するケースを確認します。さらに、テストデータを使って既存行の扱い、制約、インデックス、再起動後の履歴、validateの結果を調べます。失敗を意図したケースを作る場合は、失敗後に残るDB状態も確認します。

Testcontainersは、使い捨てのDB環境をテストから扱う手段の一つです。本番相当のデータ量での適用時間、ロック、バックアップ復元、複数台デプロイの安全性は、本番に近い複製環境で別途確認します。

たとえば既存テーブルに競合検知用のversion列を加えるなら、Flywayでは列追加の履歴を管理し、アプリケーション側の更新条件や競合判定は別に実装・テストします。楽観ロックの具体例はMySQLの楽観ロック記事を参照できます。

空のDBと既存状態からの更新を確認する

空のDBを作成して最新まで適用できるかを確認すると、新規環境のセットアップ漏れを見つけやすくなります。別のテストでは、あるバージョンまで適用したDBを用意し、次のマイグレーションだけが適用されることを確認します。両方の経路を通すことで、新規構築と継続更新の違いを検査できます。

テストデータを使って、既存行へ追加カラムの初期値がどう反映されるか、NULLや重複値が制約に違反しないか、アプリケーションの新旧バージョンが同じ期間に動けるかを見ます。マイグレーションとアプリを同時に一斉交換できない構成では、先に追加して後から制約を強める「段階的な変更」が必要になることがあります。

本番適用前の確認項目

本番適用では、SQLレビュー、接続先と権限、対象バージョン、バックアップ取得と復元確認、実行時間の見積もり、ロックや停止の影響、失敗後の連絡・復旧担当を確認します。大きなテーブルへの変更は、同じSQLでもデータ量やDB設定によって所要時間が変わります。小さなテストDBで成功したことを本番性能の根拠にせず、代表的な規模の複製環境で計測します。

アプリケーション起動時にFlywayを実行する構成では、起動とDB変更が結び付いています。複数インスタンスを同時に起動する場合や、起動順序を制御するデプロイでは、マイグレーションを誰がいつ実行するのかを明確にします。アプリケーション起動とは別のリリース工程として実行する方法もあります。どちらの場合も、利用するFlywayの排他・履歴管理だけに依存せず、デプロイ手順と監視を設計してください。

Flywayの公式資料には、versioned migration、repeatable migration、baseline、validate、schema history tableの説明があります。Spring Bootのデータ初期化ガイドは、自動設定の条件、マイグレーションファイルの場所、基本SQLスクリプトとの併用上の注意を説明しています。DB固有の挙動は、利用中のDBの公式マニュアルも合わせて確認します。

Flyway versioned migrations/repeatable migrations/baselines/validate/Spring Boot 3.5 Database Initialization/Spring Boot 3.5 Application Properties/MySQL 8.4 Statements That Cause an Implicit Commit

まとめ

Flywayを使うと、DB変更をSQLファイルと適用履歴で管理し、開発から本番まで同じ変更を順に適用しやすくなります。Spring Bootでは利用中のバージョンとDBに合う依存関係を選び、SQLの配置先、接続先、ほかの初期化方式との重複を確認します。

適用済みのversioned migrationは書き換えず、新しい変更を追加するのが基本です。既存DBへのbaselineは現状と環境差を調べてから行い、validateの検出範囲も理解して使います。MySQLなどではDDLのロールバックを一律に期待せず、DBに近い環境で変更手順を検証し、バックアップと復旧方法を用意してから本番へ適用してください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次