1. 概述
Flyway 遷移不一定能按計劃進行。在本教程中,我們將探討我們處理失敗遷移的選項。
2. 部署準備
讓我們從一個基本的 Flyway 配置的 Spring Boot 項目開始。該項目包含 flyway-core、spring-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 歷史記錄,並最終應用已更正的遷移。