StackTraces
Spring Boot已驗證

Flyway 報 Validate failed: checksum mismatch

@debug_master32 天前更新閱讀 6 min00

checksum mismatch 不是 Flyway 抽風,是它的一種保護:你改了已經應用過的遷移腳本,本地重算的 checksum 和數據庫裡存的對不上。別急著 repair,先想清楚該不該改這個腳本——長期正確做法是新增遷移,而不是原地改歷史。

Issue & Env(案發現場與環境)

  • 現象:應用啟動到 Flyway 校驗階段失敗,進程退出,數據庫連接其實已經建立好了。
  • 環境:Spring Boot 2.x / 3.x,Flyway(flyway-core + spring-boot-starter-jdbc),遷移腳本預設放在 src/main/resources/db/migration。

StackTrace(堆疊日誌)

啟動日誌裡的校驗失敗:

org.flywaydb.core.api.FlywayException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1.0
-> Applied to database : 87747630
-> Resolved locally : 1882320251
		at org.flywaydb.core.Flyway.doValidate(Flyway.java:325)
		at org.flywaydb.core.Flyway.migrate(Flyway.java:187)
		at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:36)
		at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
		at org.springframework.context.support.DefaultLifecycleProcessor.lambda$startBeans$1(DefaultLifecycleProcessor.java:152)
		at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1767)
		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
		at java.lang.Thread.run(Thread.java:750)

兩行數字是關鍵:Applied to database 是數據庫記錄的歷史 checksum,Resolved locally 是它現在根據本地腳本重算出來的值,兩者不一致就報錯。

Reproduce(復現程式碼)

數據庫已經應用過 V1__create_user.sql,之後你手賤改了它——哪怕只加一行註釋:

-- V1__create_user.sql(改前)
create table user_info (
    id bigint primary key
);
-- V1__create_user.sql(改后,加了一行注释)
-- add comment
create table user_info (
    id bigint primary key
);

再次啟動應用,Flyway 校驗階段就會拋 checksum mismatch。

Root Cause(根因分析)

Flyway 第一次應用某個遷移腳本時,把腳本內容算出一個 checksum,連同版本號、描述一起寫進 flyway_schema_history 表。之後每次啟動,Flyway 在 validate 階段會重新讀本地腳本、重算 checksum,再和表裡的歷史值比對。

只要你改了已經應用過的腳本,checksum 就變,比對自然失敗。這個機制是刻意的:它防止你把自己都不知道的歷史改動帶進各個環境,尤其是生產。常見的觸發原因有幾類:

  1. 直接編輯了已應用的 V* 腳本,哪怕只改註釋、重新格式化。
  2. 文件換行符漂移(Windows 的 CRLF 和 Unix 的 LF 混用),內容一樣 checksum 卻不同。
  3. 文件編碼不一致,腳本里含中文等非 ASCII 字符時尤其明顯。

The Fix(解決方案)

分場景處理,別一上來就 repair。

先判斷:這個腳本現在還該不該是原來的樣子。

首選——腳本不該改。 已應用的 versioned migration 就當歷史資產凍結,新變更寫成新腳本:

-- V2__add_email_column.sql
alter table user_info add column email varchar(255);

腳本被誤改。 把內容改回應用時的原樣,checksum 就恢復,不用碰數據庫。

確認新內容才是對的、且庫結構和腳本一致。 這時才用 repair 重算並更新歷史記錄:

mvn flyway:repair \
  -Dflyway.url=jdbc:mysql://localhost:3306/your_db \
  -Dflyway.user=root \
  -Dflyway.password=xxx

repair 只是把 flyway_schema_history 裡的 checksum 刷新成當前腳本的值,不改變你的表結構。生產環境用它要格外謹慎,得先確認庫裡的實際結構確實和腳本一致。

開發環境最省事。 直接重建庫,讓 Flyway 從零跑一遍:

DROP DATABASE IF EXISTS your_db;
CREATE DATABASE your_db;

編碼問題從根上防:腳本統一存成 UTF-8,並在設定裡顯式聲明:

spring.flyway.encoding=UTF-8

這樣能避免不同編輯器、不同操作系統之間的編碼漂移,從源頭少掉一類 checksum 變更。

References(參考來源)

最後更新於 2026-09-09

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法