1. 概要

フライウェイの移行は、必ずしも計画どおりに進むとは限りません。 このチュートリアルでは、失敗した移行から回復するためのオプションについて説明します。

2. 設定

基本的なFlyway構成のSpring Bootプロジェクトから始めましょう。 flyway-core spring-boot-starter-jdbc、、およびflyway-maven-pluginの依存関係があります。

構成の詳細については、がFlywayを紹介する記事を参照してください。

2.1. 構成

まず、2つの異なるプロファイルを追加しましょう。 これにより、さまざまなデータベースエンジンに対して簡単に移行を実行できるようになります。

<profile>
    <id>h2</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
	    <artifactId>h2</artifactId>
        </dependency>
    </dependencies>
</profile>
<profile>
    <id>postgre</id>
    <dependencies>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
    </dependencies>
</profile>

これらのプロファイルごとにFlywayデータベース構成ファイルも追加しましょう。

まず、application-h2.propertiesを作成します。

flyway.url=jdbc:h2:file:./testdb;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE;MODE=MySQL;DATABASE_TO_UPPER=false;
flyway.user=testuser
flyway.password=password

その後、PostgreSQL application-postgre.propertiesを作成しましょう。

flyway.url=jdbc:postgresql://127.0.0.1:5431/testdb
flyway.user=testuser
flyway.password=password

注:既存のデータベースに一致するようにPostgreSQL構成を調整するか、コードサンプルのdocker-composeファイルを使用できます。

2.2. 移行

最初の移行ファイルV1_0__add_table.sqlを追加しましょう。

create table table_one (
  id numeric primary key
);

次に、エラー V1_1__add_table.sql:を含む2番目の移行ファイルを追加しましょう。

create table <span style="color: #ff0000">table_one</span> (
  id numeric primary key
);

私たちは同じテーブル名を使用して故意にミスをした。 これにより、Flyway移行エラーが発生するはずです。

3. 移行を実行する

それでは、アプリケーションを実行して、移行を適用してみましょう。

まず、デフォルトの h2 プロファイルの場合:

mvn spring-boot:run

次に、 postgre プロファイルの場合:

mvn spring-boot:run -Ppostgre

予想どおり、最初の移行は成功しましたが、2番目の移行は失敗しました。

Migration V1_1__add_table.sql failed
...
Message    : Table "TABLE_ONE" already exists; SQL statement:

3.1. 状態を確認する

データベースの修復に進む前に、次のコマンドを実行してFlywayの移行状態を調べてみましょう。

mvn flyway:info -Ph2

これは、期待どおりに戻ります。

+-----------+---------+-------------+------+---------------------+---------+
| Category  | Version | Description | Type | Installed On        | State   |
+-----------+---------+-------------+------+---------------------+---------+
| Versioned | 1.0     | add table   | SQL  | 2020-07-17 12:57:35 | Success |
| Versioned | 1.1     | add table   | SQL  | 2020-07-17 12:57:35 | <span style="color: #ff0000">Failed</span>  |
+-----------+---------+-------------+------+---------------------+---------+

しかし、PostgreSQLの状態を次のように確認すると、次のようになります。

mvn flyway:info -Ppostgre

2番目の移行の状態は保留中であり、失敗:ではないことがわかります。

+-----------+---------+-------------+------+---------------------+---------+
| Category  | Version | Description | Type | Installed On        | State   |
+-----------+---------+-------------+------+---------------------+---------+
| Versioned | 1.0     | add table   | SQL  | 2020-07-17 12:57:48 | Success |
| Versioned | 1.1     | add table   | SQL  |                     | <span style="color: #339966">Pending</span> |
+-----------+---------+-------------+------+---------------------+---------+

違いは、 PostgreSQLがDDLトランザクションをサポートしているのに対し、H2やMySQLなどはサポートしていないという事実にあります。 その結果、PostgreSQLは失敗した移行のトランザクションをロールバックすることができました。 データベースを修復しようとすると、この違いがどのように影響するかを見てみましょう。

3.2. 間違いを修正して移行を再実行する

テーブル名をtable_oneからtable_two。に修正して、移行ファイルV1_1__add_table.sqlを修正しましょう。

それでは、アプリケーションをもう一度実行してみましょう。

mvn spring-boot:run -Ph2

H2の移行が次のように失敗することがわかります。

Validate failed: 
Detected failed migration to version 1.1 (add table)

Flywayは、バージョン1.1 の移行がすでに失敗している限り、このバージョンの移行を再実行しません。

一方、postgreプロファイルは正常に実行されました。 前述のように、ロールバックにより、状態はクリーンで、修正された移行を適用する準備ができていました。

実際、 mvn flyway:info -Ppostgre を実行すると、Successで適用された両方の移行を確認できます。 したがって、結論として、PostgreSQLの場合、私たちがしなければならなかったのは、移行スクリプトを修正し、移行を再トリガーすることだけでした。

4. データベースの状態を手動で修復する

データベースの状態を修復する最初の方法は、flyway_schema_historyテーブルからFlywayエントリを手動で削除することです。

データベースに対してこのSQLステートメントを実行してみましょう。

delete from flyway_schema_history where version = '1.1';

ここで、 mvn spring-boot:run を再度実行すると、移行が正常に適用されていることがわかります。

ただし、データベースを直接操作することは理想的ではない場合があります。 それでは、他にどのようなオプションがあるか見てみましょう。

5. フライウェイ修理

5.1. 失敗した移行を修復する

別の壊れた移行V1_2__add_table.sql file アプリケーションを実行し、移行に失敗した状態に戻ることで、先に進みましょう。

データベースの状態を修復する別の方法は、 flyway:repairツールを使用することです。 SQLファイルを修正した後、 flyway_schema_history テーブルに手動でアクセスする代わりに、次のコマンドを実行できます。

mvn flyway:repair

その結果、次のようになります。

Successfully repaired schema history table "PUBLIC"."flyway_schema_history"

舞台裏では、Flywayは失敗した移行エントリをflyway_schema_historyテーブルから削除するだけです。

これで、 flyway:info を再度実行して、最後の移行の状態がFailedからPendingに変更されたことを確認できます。

アプリケーションをもう一度実行してみましょう。 ご覧のとおり、修正された移行が正常に適用されました。

5.2. チェックサムを再調整する

通常、正常に適用された移行を変更しないことをお勧めします。 しかし、それを回避する方法がない場合があるかもしれません。

したがって、このようなシナリオでは、ファイルの先頭にコメントを追加して、移行V1_1__add_table.sqlを変更しましょう。

今すぐアプリケーションを実行すると、「移行チェックサムの不一致」エラーメッセージが次のように表示されます。

Migration checksum mismatch for migration version 1.1
-> Applied to database : 314944264
-> Resolved locally    : 1304013179

これは、すでに適用されている移行を変更し、Flywayが不整合を検出したために発生します。

でチェックサムを再調整するには、同じflyway:repairコマンドを使用できます。 ただし、今回は移行は実行されません。 flyway_schema_historyテーブルのバージョン1.1エントリのチェックサムのみが、更新された移行ファイルを反映するように更新されます。

アプリケーションを再度実行すると、修復後、アプリケーションが正常に起動したことがわかります。

この場合、Maven経由で flyway:repairを使用していることに注意してください。 もう1つの方法は、Flywayコマンドラインツールをインストールして、 flywayrepairを実行することです。 効果は同じです。flywayの修復により、失敗した移行がflyway_schema_historyテーブルから削除され、すでに適用されている移行のチェックサムが再調整されます

6. フライウェイコールバック

手動で介入したくない場合は、移行に失敗した後、失敗したエントリをflyway_schema_historyから自動的に削除する方法を検討できます。 この目的のために、 afterMigrateError Flywayコールバックを使用できます。

まず、SQLコールバックファイル db / callback /afterMigrateError__repair.sqlを作成します。

DELETE FROM flyway_schema_history WHERE success=false;

これにより、移行エラーが発生するたびに、失敗したエントリがFlywayの状態履歴から自動的に削除されます。

Flywayロケーションリストにdb/callbackフォルダーを含むapplication-callbacks.propertiesプロファイル構成を作成しましょう。

spring.flyway.locations=classpath:db/migration,classpath:db/callback

そして今、さらに別の壊れた移行 V1_3__add_table.sqlを追加した後、コールバックプロファイルを含むアプリケーションを実行します。

mvn spring-boot:run -Dspring-boot.run.profiles=h2,callbacks
...
Migrating schema "PUBLIC" to version 1.3 - add table
Migration of schema "PUBLIC" to version 1.3 - add table failed!
...
Executing SQL callback: afterMigrateError - repair

予想どおり、移行は失敗しましたが、 afterMigrateError コールバックが実行され、flyway_schema_historyがクリーンアップされました。

V1_3__add_table.sql 移行ファイルを修正し、アプリケーションを再実行するだけで、修正された移行に適用できます。

7. 概要

この記事では、失敗したFlywayの移行から回復するさまざまな方法について説明しました。

PostgreSQLのようなデータベース(つまり、DDLトランザクションをサポートするデータベース)がFlywayデータベースの状態を修復するために追加の作業を必要としないことを確認しました。

一方、このサポートがないH2のようなデータベースの場合、 Flyway修復を使用してFlyway履歴をクリーンアップし、最終的に修正された移行を適用する方法を確認しました。

いつものように、完全なコードはGitHub利用できます。