この記事では、Flyway を使用して Spring Boot アプリケーションで SQL データベース スキーマを管理する方法を説明します。
この記事では、Flyway を使用して Spring Boot アプリケーションで SQL データベース スキーマを管理する方法を説明します。
Flyway は、移行履歴とロールバック機能を提供するデータベース移行ツールで、アプリケーションのデータベース スキーマ関連レイヤーをデータベース エンティティ レイヤーから分離できるようにします。
アプリケーションの設定
私たちが使用する Spring Boot アプリケーションは、この Spring Initializr リンクを使用して生成できます。必要な依存関係がすべて含まれています。
アプリケーションをダウンロードして依存関係を解決した後、spring-boot-flyway という新しい Postgres データベースを作成し、それに接続するようにアプリケーションを構成します。
リスト 2.1 application.properties :
spring.datasource.url=jdbc:postgresql://localhost:5432/spring-boot-flyway
spring.datasource.username=demo
spring.datasource.password=demo
デフォルトでは、Flyway はクラスパス内のdb/migration/ディレクトリを検索して、データベース テーブルとレコードを管理するための SQL ステートメントを含む移行ファイルを探します。
古いバージョンのライブラリの場合、エラーを回避するために、 resources/db/migration/ に.keepという空のテキスト ファイルを作成して、このディレクトリがコンパイルされ、アプリケーションの起動時に使用できるようにする必要がある場合があります。
これが完了すると、アプリケーションを起動できるようになり、正常に実行されるはずです。
基本的な使い方
Flyway の動作方法は、セクション 2 で Flyway の依存関係をクラスパスに追加したため、resources/db/migration ディレクトリに移行ファイルを作成し、Spring Boot が自動的に移行スクリプトを実行することです。
リスト 3.1 V1__Users.sql :
CREATE TABLE IF NOT EXISTS users
(
id SERIAL,
email VARCHAR(200) NOT NULL,
name VARCHAR(200) NOT NULL,
PRIMARY KEY (id)
);
リスト 3.1 のコード スニペットを見てみましょう。ファイル名V1__Users.sql は、特定の規則に従います。
- 「 V 」は、これがバージョン管理された移行であることを示します。
- Vの後の 「 1 」は実際のバージョン番号です。「 V1_1 」にすることもできます。これはバージョン 1.1 に変換されます。
- その後に区切り文字「 __ 」(2 つのアンダースコア)が続きます 。これにより、移行ファイルの名前 (この場合はユーザー) からバージョン情報が分離されます。
- 最後の部分「 .sql 」は拡張子であるため、ファイルには単純な SQL ステートメントが含まれています。
この時点で、アプリケーションを再起動すると、データベースにユーザー テーブルが作成されます。また、明示的に作成していない別のテーブルFlyway_schema_history があることもわかります 。
Flyway_schema_history は、適用された移行を追跡するために Flyway 自体によって使用されます。このテーブルが存在しない場合、Flyway はデータベースを初めて初期化していると想定し、すべての移行をバージョン番号順に実行します。
Flyway_schema_historyテーブルが存在する場合、Flyway は以前に適用されていない新しい移行ファイルのみを適用します。つまり、新しいテーブルを追加するには、更新されたバージョン番号を持つ更新された移行ファイルを作成し、アプリケーションを再起動するだけで済みます。
SQL を使用する代わりに、Javaで移行スクリプトを作成することもできます。Java 移行スタイルでは、移行ファイルは抽象BaseJavaMigration
クラスを拡張し、migrate
メソッドを実装する必要がある Java クラスです。
IDE は通常、Java クラスがリソースディレクトリにあることを想定していないため、 src/main/java にdb/migration という新しいパッケージを作成します。この新しいパッケージdb/migration はsrc/main/javディレクトリに配置する必要があることを知っておくことが非常に重要です。
新しい Java 移行を作成して、新しいテーブルを追加しましょう。
リスト 3.2 V2__Posts.java :
public class V2__Posts extends BaseJavaMigration {
@Override
public void migrate(Context context) throws Exception {
var sql = """
CREATE TABLE posts (
id SERIAL,
author_id INT NOT NULL,
post TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
""";
try(var statement = context.getConnection().createStatement()) {
statement.execute(sql);
}
}
}
SQL ファイルではなく Java 移行を使用する利点は、単純な SQL では不可能なカスタム ロジック、条件、検証を追加できることです。たとえば、別のテーブルが存在するかどうかを確認したり、環境から値を取得したりできます。
もうお気づきかと思いますが、はい、Flyway の場所が両方の場合で同じであることを確認する限り、同じコードベース内で SQL スタイルの移行と Java スタイルの移行を混在させることができます。
フライウェイの構成とカスタマイズ
これまでは、デフォルトの Flyway 動作を使用してきました。ニーズに合わせて Flyway をさらに調整できます。たとえば、移行ファイルのデフォルトの場所を変更したり、データベース スキーマ (別名テーブルスペース) を構成したり、SQL 移行プレフィックスを「V」から任意のものに変更したりできます。
以下の構成では、本番環境での誤った使用を防ぐために、移行ファイルが配置されているパスを構成し、データベースのクリーニング (つまり、すべてのテーブルの削除) を無効にします。
リスト 4.1 application.properties:
spring.flyway.locations=classpath:migrations
spring.flyway.clean-disabled=true
このキーの下には、spring.flyway
ライブラリの動作を微調整するために使用できる他の構成可能なプロパティがあります。また、 Flyway のドキュメントページも参考にしてください。
飛行経路コールバック
Flyway は、移行プロセスのさまざまな段階で呼び出すことができるコールバックを構成する機能を提供します。コールバック メカニズムは、移行ライフサイクルのさまざまな段階で特定のアクションを実行する便利な方法です。
アプリケーションの起動時にシードするデフォルト データがあるとします。このイベントをサポートするコールバックを作成するだけですAFTER_MIGRATE
。
リスト 5.1 FlywayDatabaseSeeder.java:
public class FlywayDatabaseSeeder implements Callback {
@Override
public boolean supports(Event event, Context context) {
return event.name().equals(Event.AFTER_MIGRATE.name());
}
@Override
public void handle(Event event, Context context) {
try(var statement = context.getConnection().createStatement()) {
var ADMIN_EMAIL = "[email protected]";
var checkQuery = "SELECT id FROM users WHERE email = %s"
.formatted(ADMIN_EMAIL);
statement.execute(checkQuery);
ResultSet resultSet = statement.getResultSet();
resultSet.last();
//return if the seeder has already been executed
if(resultSet.getRow() >= 0) return;
var sql = """
INSERT INTO users (email, name) VALUES
('%s', 'Super Admin')
""".formatted(ADMIN_EMAIL);
statement.execute(sql);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean canHandleInTransaction(Event event, Context context) {
return true;
}
@Override
public String getCallbackName() {
return FlywayDatabaseSeeder.class.getName();
}
}
上記のリストでは、メソッド内で、このコールバックがイベントに対してのみ実行されることsupports
を宣言し、メソッド内で、デフォルトのスーパー管理者ユーザーがまだ存在しない場合にそれを挿入するロジックの概要を示しています。AFTER_MIGRATE
handle
その前に、SpringBoot の Flyway にコールバック クラスを登録する必要があります。FlywayMigrationStrategy
これを行うには、Bean を作成します。
リスト 5.2 SpringBootFlywayApplication.java :
@Bean
public FlywayMigrationStrategy flywayMigrationStrategy() {
return (flywayOld) -> {
/*
Update the existing autoconfigured Flyway
bean to include our callback class
*/
Flyway flyway = Flyway.configure()
.configuration(flywayOld.getConfiguration())
.callbacks(new FlywayDatabaseSeeder())
.load();
flyway.migrate();
};
}
rg.flywaydb.core.api.callback.Event列挙には他のイベントがあり、サポートするクラスを 構成できます。Callback
たとえば、AFTER_MIGRATE_ERROR
イベントをサポートするコールバックを用意し、Slack 通知を送信してエンジニアに警告することができます。
ヒントとコツ
ローカル環境で開発する場合、 Flyway_schema_history テーブルから移行エントリを削除できます。
次回アプリを起動すると、履歴を削除したマイグレーションが再度実行されます。こうすることで、データベース全体を削除せずに、ローカル マシンで開発を続けながらエラーを修正したり、スキーマを更新したりできます。
また、SpringBoot では、アプリケーションの起動時に Flyway が移行スクリプトを実行するタイミングを制御できます。たとえば、ローカル環境での移行を自動化したくないとします。次のことができます。
リスト 6.1 SpringBootFlywayApplication.java:
@Bean
public FlywayMigrationStrategy flywayMigrationStrategy(@Value("${spring.profiles.active}") String activeProfile) {
return (flywayOld) -> {
/*
Update the existing autoconfigured Flyway
bean to include our callback class
*/
Flyway flyway = Flyway.configure()
.configuration(flywayOld.getConfiguration())
.callbacks(new FlywayDatabaseSeeder())
.load();
if(!"local".equalsIgnoreCase(activeProfile)) {
flyway.migrate();
}
};
}
結論は
データベース移行ツールを使用する利点の 1 つは、データベース スキーマがアプリケーション コード ベースの一部になることです。アプリケーションには中心的な参照点があるため、データベースへの変更を時間の経過とともに追跡することが容易になります。