0
0
0

Flyway 原理与实战

文章摘要
|

Flyway 原理与使用

Flyway 是一个数据库版本迁移工具。

可以简单理解为:

Git     → 管代码变更历史
Flyway  → 管数据库变更历史

理解 Flyway,核心记住一句话:

Migration 是否执行,看 flyway_schema_history 中有没有成功记录;已经执行过的 Migration 有没有被修改,看 checksum 是否一致。


一、为什么需要 Flyway

数据库结构会不断变化:

CREATE TABLE sys_user (...);

ALTER TABLE sys_user
ADD COLUMN phone VARCHAR(20);

CREATE INDEX idx_user_phone
ON sys_user(phone);

如果全部人工执行,很容易出现开发、测试、生产环境数据库结构不一致。

Flyway 的做法是把每次数据库变更做成一个版本:

V1__init.sql
V2__create_user.sql
V3__add_user_phone.sql
V4__add_user_index.sql

数据库结构就按照:

V1 → V2 → V3 → V4

逐步演进。


二、Flyway 的核心原理

Flyway 会维护一张表:

flyway_schema_history

其中比较重要的信息有:

version

script

checksum

success

1

V1__init.sql

125634

1

2

V2__create_user.sql

986421

1

假设项目中有:

V1
V2
V3

数据库已经有:

V1 success
V2 success

那么启动时:

V1 → 已执行 → 跳过
V2 → 已执行 → 跳过
V3 → 没记录 → 执行

所以 Flyway 并不是重复执行所有 SQL,而是根据 flyway_schema_history 判断哪些版本没有执行。

这也解释了为什么业务数据被修改或删除后,旧 Migration 不会重新执行。

例如 V2 曾经插入:

INSERT INTO sys_user(id, username)
VALUES (1, 'admin');

后来这条数据被删除,Flyway 也不会重新插入,因为:

V2 已经有成功记录

Flyway 管的是数据库变更历史,不是当前业务数据。


三、checksum 和 Migration 修改

Flyway 会给每个 Migration 计算一个:

checksum

可以理解成 SQL 文件的指纹。

假设 V2 第一次执行时:

checksum = 123456

后来你修改了 V2,新的 checksum 变成:

789012

启动时 Flyway 发现:

数据库记录:123456
当前文件:  789012

就会报:

checksum mismatch

Spring Boot 集成 Flyway 时,通常会导致:

Flyway 校验失败
→ Spring Boot 启动失败

所以原则很简单:

已经成功执行过的 Versioned Migration 不要修改,有新的数据库变化就新增版本。

例如:

V1
V2
V3
V4

一直向后增加。

Migration 命名格式:

V版本号__描述.sql

例如:

V3__add_user_phone.sql

版本号和描述之间必须使用两个下划线 __。

多人项目可以用时间戳减少版本冲突:

V202610211030__add_device_status.sql

四、Migration 执行失败的坑

假设:

V1 成功
V2 失败

V1 不会因为 V2 失败而回滚。

并且在 MySQL 中,V2 文件内部也不能认为一定全部回滚。

例如:

ALTER TABLE sys_user ADD COLUMN age INT;

ALTER TABLE sys_user ADD COLUMN phone VARCHAR(20);

ALTER TABLE not_exist_table ADD COLUMN test VARCHAR(20);

可能出现:

age 已添加
phone 已添加
第三条失败

所以 Migration 执行失败后,不要直接修改 SQL 然后重启。

应该先:

检查数据库实际状态
→ 确认哪些 SQL 已执行
→ 处理已经产生的修改
→ 再重新执行

否则可能出现:

Duplicate column

五、老项目怎么引入 Flyway

新项目

最简单的方式是项目刚创建时就引入 Flyway:

V1 → V2 → V3 → V4

从一开始就完整管理数据库版本。

老项目

老项目已经有很多表和数据,不能重新执行 V1,所以需要:

Baseline

Baseline 可以理解为:

告诉 Flyway:当前数据库已经处于某个版本,从后面的版本开始执行。

例如:

spring:
  flyway:
    baseline-on-migrate: true
    baseline-version: 1

表示:

当前老数据库已经是 V1

那么:

V1 → 不执行
V2 → 执行
V3 → 执行

如果:

baseline-version: 2

则表示:

当前老数据库已经是 V2

那么:

V1 → 不执行
V2 → 不执行
V3 → 执行

所以直接记:

baseline-version=N 表示当前老数据库已经处于 V N,小于等于版本N 的 Migration 都不会执行。

baseline-on-migrate 一般只在老项目第一次接入 Flyway 时开启。

Baseline 成功、flyway_schema_history 已经建立后,建议关闭。

以后新增:

V2
V3
V4
...

正常按 Flyway 版本继续管理即可。

老项目也可以整理一个完整的:

V1__baseline.sql

已有数据库 Baseline 到 V1,不执行 V1。

以后创建新的空数据库时,可以正常:

V1 → V2 → V3

这样新老数据库最终使用同一套 Flyway 版本体系。


六、总结

Flyway 最核心就是:

Migration
    ↓
flyway_schema_history
    ↓
version  → 判断执行过没有
checksum → 判断历史文件有没有被修改

记住下面几条就够了:

  1. Flyway 管数据库变更历史。

  2. flyway_schema_history 记录 Migration 执行情况。

  3. 没有成功记录的新版本才执行。

  4. 已执行 Migration 被修改会导致 checksum mismatch。

  5. 已执行的 Versioned Migration 不要修改,继续新增版本。

  6. MySQL Migration 失败后要检查数据库实际状态。

  7. 新项目最好一开始就使用 Flyway。

  8. 老项目通过 Baseline 接入。

  9. baseline-version=N 表示数据库已经处于 VN。

  10. baseline-on-migrate 一般首次接入时开启,成功后关闭。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论