はじめに
Spring BootアプリケーションでFlywayを使用したデータベースマイグレーションは一般的ですが、Repeatable Migration(R__ファイル)の活用方法について詳しく解説している記事は少ないと感じています。
本記事では、実際のプロジェクトでの調査を通じて分かった、Repeatable Migrationの仕組みと実践的な活用方法について詳しく解説します。
Repeatable Migrationとは
通常のMigration(V__)との違い
種類 | ファイル名例 | 実行タイミング | 用途 |
---|---|---|---|
Version Migration | V1_1__create_user_table.sql |
1回のみ実行 | DDL(テーブル作成・変更) |
Repeatable Migration | R__insert_initial_data.sql |
チェックサム変更時に再実行 | 初期データ投入・ビュー再作成 |
チェックサムによる再実行の仕組み
FlywayはRepeatable Migrationファイルの内容からMD5ハッシュ(チェックサム)を計算し、flyway_schema_history
テーブルに保存します。
-- flyway_schema_historyテーブルの構造
CREATE TABLE flyway_schema_history (
installed_rank INT NOT NULL,
version VARCHAR(50),
description VARCHAR(200) NOT NULL,
type VARCHAR(20) NOT NULL,
script VARCHAR(1000) NOT NULL,
checksum INT, -- チェックサムが保存される
installed_by VARCHAR(100) NOT NULL,
installed_on TIMESTAMP NOT NULL,
execution_time INT NOT NULL,
success BOOLEAN NOT NULL
);
チェックサム変更による再実行の例
初回実行時:
-- R__insert_initial_data.sql
INSERT INTO users (email, display_name)
VALUES ('admin@example.com', '管理者');
→ チェックサム: 123456789
ファイル内容を変更:
-- R__insert_initial_data.sql
INSERT INTO users (email, display_name)
VALUES ('admin@example.com', 'システム管理者'); -- 変更
→ 新しいチェックサム: 987654321
→ ファイルが再実行される
実践的な活用例
1. 環境別設定による本番環境の保護
開発環境でのみ初期データを投入し、本番環境では実行しない設定方法:
# application.yaml(デフォルト・本番環境)
spring:
flyway:
locations: classpath:db/migration # V__ファイルのみ
# application-local.yaml(ローカル開発環境)
spring:
flyway:
locations: classpath:db/migration, classpath:db/local_initial_data # V__とR__両方
この設定により:
- 本番環境: DDLのみ実行(テーブル作成・変更)
- 開発環境: DDL + 初期データ投入
2. 冪等性を保つためのTRUNCATEパターン
Repeatable Migrationでは必ずデータをクリアしてから挿入します:
-- R__insert_initial_data.sql
SET foreign_key_checks = 0;
TRUNCATE TABLE users;
TRUNCATE TABLE roles;
SET foreign_key_checks = 1;
-- 初期ユーザーデータの投入
-- password: password123
INSERT INTO users (password, email, display_name, created_at)
VALUES ('$2a$12$DsXCyUnQa0Gk2IBSjqnADeOIDU1.yd7gtpy4I9b08wr.elKt5IOUO',
'admin@example.com', '管理者', '2024-01-01 12:00:00');
INSERT INTO users (password, email, display_name, created_at)
VALUES ('$2a$12$DsXCyUnQa0Gk2IBSjqnADeOIDU1.yd7gtpy4I9b08wr.elKt5IOUO',
'user@example.com', '一般ユーザー', '2024-01-01 12:00:00');
-- ロールデータの投入
INSERT INTO roles (name, description) VALUES
('ADMIN', '管理者権限'),
('USER', '一般ユーザー権限');
3. docker-composeでの自動初期化
# docker-compose.yml
services:
app:
environment:
- SPRING_PROFILES_ACTIVE=local # localプロファイルで起動
depends_on:
- database
database:
image: mysql:8.0
environment:
MYSQL_DATABASE: myapp
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: rootpassword
このように設定することで、docker-compose起動時に:
- MySQLコンテナが起動
- Spring Bootアプリケーションが起動
- Flywayが自動実行される
- V__ファイル(テーブル作成)→ R__ファイル(初期データ投入)の順で実行
- 開発者がすぐにログインできる状態が完成
チーム開発での活用メリット
1. 開発環境の統一
チームメンバー全員が同じ初期データでテストできます:
# 新しいメンバーがjoinした場合
git clone <repository>
cd backend
docker-compose up
# → 即座にテスト可能な環境が構築される
2. テストデータの共有と更新
開発者Aがテストデータを追加:
-- R__insert_initial_data.sqlに新しいユーザーを追加
INSERT INTO users (...) VALUES (..., 'developer@example.com', ...);
他の開発者は次回アプリ起動時に自動的に新しいデータが反映されます。
3. データ駆動開発の支援
画面開発時に必要な様々なパターンのテストデータを用意:
-- 様々な状態のタスクデータ
INSERT INTO tasks (title, status, assignee_id) VALUES
('開発タスク1', 'TODO', 1), -- 未着手
('開発タスク2', 'IN_PROGRESS', 1), -- 進行中
('開発タスク3', 'DONE', 2), -- 完了
('開発タスク4', 'CANCELLED', 2); -- キャンセル
注意点とベストプラクティス
1. チェックサム変更の落とし穴
以下の変更でもチェックサムが変わり、再実行されます:
- 文字エンコーディングの変更
- 改行コードの変更(LF ↔ CRLF)
- 末尾の空白の追加・削除
- コメントの追加・変更
2. 大量データでのパフォーマンス考慮
Repeatable Migrationは毎回全データを削除→再挿入するため:
- 適用対象: 小規模な初期データ(ユーザー、マスターデータなど)
- 不適切: 大量のトランザクションデータ
3. 実行順序の理解
V1_1__create_user_table.sql # 1. 通常のMigration(バージョン順)
V1_2__create_session_table.sql # 2. 通常のMigration(バージョン順)
R__insert_master_data.sql # 3. Repeatable(アルファベット順)
R__insert_user_data.sql # 4. Repeatable(アルファベット順)
実際のチェックサム確認方法
現在のファイルのチェックサムを確認:
# macOS/Linux
md5 R__insert_initial_data.sql
# MD5 (R__insert_initial_data.sql) = 8c10695ad48043486987cfef9a744561
# Windows
certutil -hashfile R__insert_initial_data.sql MD5
よくある問題とトラブルシューティング
1. エラーが発生した場合の対処
-- 外部キー制約エラーを避けるため
SET foreign_key_checks = 0;
-- データ投入処理
SET foreign_key_checks = 1;
2. 既存データとの競合
-- INSERT時の重複エラーを回避
INSERT IGNORE INTO users (...) VALUES (...);
-- または ON DUPLICATE KEY UPDATE を使用
INSERT INTO users (id, email, name) VALUES (1, 'admin@example.com', '管理者')
ON DUPLICATE KEY UPDATE name = VALUES(name);
まとめ
Repeatable Migrationを活用することで:
- 開発効率の向上: 初期データ準備の自動化
- チーム開発の円滑化: 統一されたテスト環境
- 本番環境の安全性: 環境別設定による適切な分離
- データ駆動開発の支援: 様々なパターンのテストデータ管理
が実現できます。
特に、Spring BootのProfile機能と組み合わせることで、開発環境では豊富な初期データを自動投入しつつ、本番環境では安全にDDLのみを適用するという理想的な運用が可能になります。
ぜひ、あなたのプロジェクトでもRepeatable Migrationを活用して、開発体験を向上させてみてください!