bigywater.tech
Spring · 99

Flyway:迁移顺序、校验和与失败后的状态

Flyway 的脚本按什么顺序执行?改了已经执行过的脚本会怎样?脚本执行到一半失败了库是什么状态?已有表的库怎么接入?这篇在 Spring Boot 4.0.8、Flyway 11、MySQL 上逐个实测。

1407251784 对 1460908494
改了已执行的 V2 脚本之后,库里记录的校验和与本地脚本的校验和
t2 留在库里
V2 脚本第二条语句失败后,第一条建的表仍然存在,历史表记录 success=0
V1 被跳过
baseline-on-migrate=true 时基线版本默认是 1,V1__create_a.sql 没有执行

执行顺序

实测 · 本机执行输出
  V1、V2、V10、V1_1 四个脚本:启动成功
    历史表:4 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 1.1 "alter a" SQL checksum 869508972 success=1
      rank 3 version 2 "create b" SQL checksum 1407251784 success=1
      rank 4 version 10 "create c" SQL checksum -1138581898 success=1
    业务表:['a', 'b', 'c']

按版本号的数值顺序,V1_1 是 1.1;历史表记录每次的校验和与成功与否。

校验和

实测 · 本机执行输出
  V2 的内容被改了一个字符之后再启动:启动失败
    Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation ‖ Migration checksum mismatch for migration version 2 ‖ -> Applied to database : 1407251784 ‖ -> Resolved locally    : 1460908494
    历史表:2 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 2 "create b" SQL checksum 1407251784 success=1
    业务表:['a', 'b']
  可重复迁移 R__view_a.sql 改了内容之后再启动:启动成功
    历史表:3 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version None "view a" SQL checksum 924199270 success=1
      rank 3 version None "view a" SQL checksum 1391577623 success=1
    业务表:['a', 'va']

改了已执行的 V 脚本启动失败;R 脚本改了就重跑。

乱序

实测 · 本机执行输出
  默认(out-of-order=false):启动失败
    Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation ‖ Detected resolved migration not applied to database: 1.5.
    历史表:2 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 2 "create b" SQL checksum 1407251784 success=1
    业务表:['a', 'b']
  spring.flyway.out-of-order=true:启动成功
    历史表:3 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 2 "create b" SQL checksum 1407251784 success=1
      rank 3 version 1.5 "late" SQL checksum 531052471 success=1
    业务表:['a', 'b', 'late']

迟到的小版本号脚本默认校验失败,out-of-order=true 才补执行。

失败状态

实测 · 本机执行输出
  V2 里第一条建表成功、第二条出错:启动失败
    Caused by: org.flywaydb.core.internal.sqlscript.FlywaySqlScriptException: Failed to execute script V2__two_statements.sql ‖ SQL State  : 42S02 ‖ Message    : Table 'demo.no_such_table' doesn't exist ‖ Line       : 2 ‖ Statement  : Run Flyway with -X option to see the actual statement causing the problem
    历史表:2 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 2 "two statements" SQL checksum 1582595889 success=0
    业务表:['a', 't2']
  不改任何东西再启动一次:启动失败
    Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation ‖ Detected failed migration to version 2 (two statements).
    历史表:2 行
      rank 1 version 1 "create a" SQL checksum -1193849269 success=1
      rank 2 version 2 "two statements" SQL checksum 1582595889 success=0
    业务表:['a', 't2']

MySQL 的 DDL 不能回滚,脚本中途失败留下半截对象和 success=0 的行,需要 repair 加手工清理。

接入已有库

实测 · 本机执行输出
  库里已有 legacy 表、没有历史表:启动失败
    Caused by: org.flywaydb.core.api.FlywayException: Found non-empty schema(s) `demo` but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
    历史表:(没有 flyway_schema_history)
    业务表:['legacy']
  spring.flyway.baseline-on-migrate=true:启动成功
    历史表:2 行
      rank 1 version 1 "<< Flyway Baseline >>" BASELINE checksum None success=1
      rank 2 version 2 "create b" SQL checksum 1407251784 success=1
    业务表:['b', 'legacy']

非空库默认拒绝;baseline-on-migrate 的基线版本默认 1,会跳过 V1。

分步演示

Flyway
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动(Flyway 11.14.1,spring-boot-starter-flyway 与 flyway-mysql;MySQL 是本机自己起的 26.7.0 实例,mysql-connector-j)。迁移脚本放在 classpath 的 db/migration 下,每个场景重建库并独立启动一次应用(非 Web),失败信息取自异常链里 Flyway 的异常以及相关的详情行,历史表内容直接用 SQL 查询
    • 没有验证:flyway repair 实际清理失败记录的过程(只验证了失败后的状态);回调(callbacks)与 Java 迁移;undo 迁移(商业版);多个 schema 与 placeholders;事务性 DDL 的数据库(如 PostgreSQL)里中途失败的行为;validate-on-migrate 关闭的后果;大表变更对线上锁的影响;Liquibase 的对比
    京ICP备2026067502号-1京公网安备11010502063487号