知識庫 / Spring / Spring Boot RSS 訂閱

Flyway 修復與 Spring Boot

Persistence,Spring Boot
HongKong
4
12:52 PM · Dec 06 ,2025

1. 概述

Flyway 遷移不一定能按計劃進行。在本教程中,我們將探討我們處理失敗遷移的選項

2. 部署準備

讓我們從一個基本的 Flyway 配置的 Spring Boot 項目開始。該項目包含 flyway-corespring-boot-starter-jdbc以及 flyway-maven-plugin 依賴項。

有關更多配置詳情,請參閲我們介紹 Flyway 的文章。

2.1. 配置

首先,讓我們添加兩個不同的配置文件。這將使我們能夠輕鬆地針對不同的數據庫引擎運行遷移:

<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>

讓我們也添加針對每個 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
<p>然後,我們創建 PostgreSQL <em >application-postgre.properties</em> 應用程序:</p>
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:

create table table_one (
  id numeric primary key
);

我們故意使用了相同的表名,導致了 Flyway 遷移錯誤。

3. 運行遷移

現在,讓我們運行應用程序並嘗試應用遷移。

首先,針對默認的 h2 配置文件:

mvn spring-boot:run

然後,針對 PostgreSQL 配置文件:

mvn spring-boot:run -Ppostgre

正如預期的那樣,第一次遷移成功,而第二次則失敗:

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 | Failed  |
+-----------+---------+-------------+------+---------------------+---------+

當我們使用以下命令檢查 PostgreSQL 的狀態時:

mvn flyway:info -Ppostgre

我們注意到第二次遷移的狀態是 待定,而不是 失敗

+-----------+---------+-------------+------+---------------------+---------+
| 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  |                     | Pending |
+-----------+---------+-------------+------+---------------------+---------+

差異在於 PostgreSQL 支持 DDL 事務,而像 H2 或 MySQL 這樣的數據庫則不支持。因此,PostgreSQL 能夠回滾失敗的遷移事務。讓我們看看這種差異如何影響我們在嘗試修復數據庫時的情況。

3.2. 修正錯誤並重新運行遷移

請修正遷移文件 V1_1__add_table.sql,將表名從 table_one 更改為 table_two

現在,讓我們嘗試重新運行應用程序:

mvn spring-boot:run -Ph2

我們現在注意到 H2 遷移失敗時,會伴隨以下情況:

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

Flyway 不會重新運行 version 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. Flyway 修復

Flyway 修復功能允許你解決數據庫遷移過程中可能出現的衝突或錯誤。當多個遷移同時嘗試修改同一行或列時,可能會導致衝突。Flyway 提供了機制來檢測和解決這些衝突,確保數據庫狀態的一致性。

以下是 Flyway 修復的一些關鍵方面:

  • 衝突檢測: Flyway 會自動檢測數據庫遷移之間的衝突。
  • 衝突解決: Flyway 嘗試自動解決衝突,但有時需要手動干預。
  • 回滾: 如果修復失敗,Flyway 可以回滾已執行的遷移,以恢復數據庫到之前的狀態。
  • 日誌記錄: Flyway 會記錄修復過程中的所有操作,方便排查問題。
// 修復數據庫遷移
Flyway flyway = new Flyway();
flyway.repair();

5.1. 修復失敗的遷移

讓我們繼續操作,添加一個損壞的遷移文件 <em V1_2__add_table.sql</em>,運行應用程序,並回到一個失敗遷移的狀態。

另一種修復數據庫狀態的方法是使用 <em <a href="https://flywaydb.org/documentation/command/repair">flyway:repair</a></em> 工具。 修正 SQL 文件後,而不是手動修改 <em flyway_schema_history</em> 表,我們可以直接運行:

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 命令。 但是,這次不會執行任何遷移。 僅更新 version 1.1 條目在 flyway_schema_history 表中的校驗和,以反映更新後的遷移文件。

在修復後再次運行應用程序,我們注意到應用程序現在可以成功啓動。

請注意,在本例中,我們通過 Maven 使用了 flyway:repair。 另一種方法是安裝 Flyway 命令行工具並運行 flyway repair。 效果相同: flyway repair 將從 flyway_schema_history 表中刪除失敗的遷移並重新對齊已應用遷移的校驗和。

6. Flyway 回調

如果不想手動干預,我們可以考慮一種在失敗遷移後自動清理 flyway_schema_history 中失敗條目的方法。為此,我們可以使用 afterMigrateError Flyway 回調。

我們首先創建 SQL 回調文件 db/callback/afterMigrateError__repair.sql:

DELETE FROM flyway_schema_history WHERE success=false;

這將自動從 Flyway 狀態歷史記錄中刪除任何失敗的條目,無論遷移過程中是否發生錯誤。

讓我們創建一個 application-callbacks.properties 配置文件,其中包含 db/callback 文件夾在 Flyway 位置列表中。

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 歷史記錄,並最終應用已更正的遷移。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.