3. Flyway快速入门:Spring Boot集成Flyway配置、基础迁移脚本编写(V1__init.sql)、首次启动验证

本章是Flyway实战的起点。我们将从零搭建一个Spring Boot项目,完成Flyway依赖引入、核心参数配置、编写第一条版本化迁移脚本 V1__init.sql,并通过首次启动验证数据库表结构是否按预期创建。掌握本章内容后,你就能在自己的项目中快速落地Flyway,为后续的异步任务与性能调优打下坚实基础。

3.1 整体流程概览

Flyway与Spring Boot集成的核心流程分为四个步骤:引入依赖 → 配置数据源与Flyway参数 → 编写迁移脚本 → 启动验证。下图展示了从项目初始化到数据库表创建完成的完整链路。

Spring Boot 集成 Flyway 快速入门流程 引入 Flyway 依赖 pom.xml / build.gradle 配置数据源 & Flyway application.yml 编写迁移脚本 V1__init.sql 启动应用 验证 flyway_schema_history 💡 关键点: Flyway 在应用启动时自动扫描 classpath:db/migration 目录下的 .sql 文件,按版本号顺序执行,并将执行记录写入 flyway_schema_history 表。 📌 版本号命名规则: V + 版本号 + __ + 描述(两个下划线)。例如:V1__init.sql、V2__add_users.sql

3.2 第一步:引入Flyway依赖

在Spring Boot项目中,引入Flyway只需在构建文件中添加一个starter依赖。Spring Boot的自动配置机制会检测到该依赖,并自动启用Flyway。

Maven (pom.xml)

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-mysql</artifactId>
    <!-- 如果使用MySQL,需要此扩展 -->
</dependency>

Gradle (build.gradle)

implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'  // MySQL专用
版本兼容提示: Spring Boot 3.x 默认使用 Flyway 9.x,无需手动指定版本。如果使用 MySQL 8.0+,请确保 flyway-mysql 扩展已添加,否则 Flyway 无法识别 MySQL 方言。

3.3 第二步:配置数据源与Flyway参数

在 application.yml 中配置数据库连接信息以及Flyway的行为参数。以下是最小化配置示例:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
    username: root
    password: root123
    driver-class-name: com.mysql.cj.jdbc.Driver
  flyway:
    enabled: true                    # 启用Flyway(默认true)
    locations: classpath:db/migration # 迁移脚本存放路径(默认值)
    baseline-on-migrate: true        # 对非空数据库执行基线迁移
    validate-on-migrate: true        # 迁移时校验已执行脚本是否被修改

下表列出了最常用的Flyway配置项及其说明:

配置项 默认值 说明
spring.flyway.enabled true 是否启用Flyway自动迁移
spring.flyway.locations classpath:db/migration 迁移脚本所在路径,支持多个路径用逗号分隔
spring.flyway.baseline-on-migrate false 当目标数据库非空且无flyway_schema_history表时,是否自动执行基线迁移
spring.flyway.validate-on-migrate true 迁移时校验已执行脚本的校验和是否与当前文件一致
spring.flyway.table flyway_schema_history Flyway元数据表名,可自定义
spring.flyway.out-of-order false 是否允许乱序执行迁移脚本(生产环境慎用)

3.4 第三步:编写基础迁移脚本 V1__init.sql

在 src/main/resources/db/migration 目录下创建第一个迁移文件。文件名必须严格遵循 V{版本号}__{描述}.sql 格式,版本号从1开始递增。

以下是一个典型的初始化脚本,创建用户表和角色表:

-- ============================================
-- V1__init.sql
-- 描述:初始化用户表和角色表
-- 版本:1
-- ============================================

CREATE TABLE IF NOT EXISTS `sys_user` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `username` VARCHAR(50) NOT NULL COMMENT '用户名',
    `password` VARCHAR(255) NOT NULL COMMENT '密码',
    `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
    `status` TINYINT DEFAULT 1 COMMENT '状态:1-启用 0-禁用',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

CREATE TABLE IF NOT EXISTS `sys_role` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `role_name` VARCHAR(50) NOT NULL COMMENT '角色名称',
    `role_code` VARCHAR(50) NOT NULL COMMENT '角色编码',
    `description` VARCHAR(255) DEFAULT NULL COMMENT '角色描述',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_role_code` (`role_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

-- 插入初始数据
INSERT INTO `sys_role` (`role_name`, `role_code`, `description`) VALUES
('管理员', 'ADMIN', '系统管理员,拥有所有权限'),
('普通用户', 'USER', '普通用户,拥有基础权限');
⚠️ 脚本编写注意事项:
  • 每个迁移脚本只做一件事,保持原子性。
  • 尽量使用 IF NOT EXISTS 或 CREATE OR REPLACE 保证幂等性。
  • 不要修改已执行过的脚本内容,否则 validate-on-migrate 会报校验和错误。
  • DDL 和 DML 可以放在同一个脚本中,但建议将数据初始化单独拆分为 V2__seed_data.sql。

3.5 第四步:首次启动验证

完成以上配置后,启动Spring Boot应用。观察控制台日志,你会看到类似以下的输出:

2025-01-15 10:23:45.123  INFO 12345 --- [main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.22.3 by Redgate
2025-01-15 10:23:45.456  INFO 12345 --- [main] o.f.c.internal.database.base.DatabaseType: Database: jdbc:mysql://localhost:3306/demo_db (MySQL 8.0)
2025-01-15 10:23:45.789  INFO 12345 --- [main] o.f.core.internal.command.DbMigrate      : Current version of schema `demo_db`: << Empty Schema >>
2025-01-15 10:23:46.012  INFO 12345 --- [main] o.f.core.internal.command.DbMigrate      : Migrating schema `demo_db` to version "1 - init"
2025-01-15 10:23:46.345  INFO 12345 --- [main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `demo_db` (execution time 00:00.533s)

验证成功的三个标志:

  1. 日志无ERROR:Flyway成功执行了迁移,并打印了 Successfully applied 信息。
  2. 数据库表已创建:登录MySQL客户端,执行 SHOW TABLES;,可以看到 sys_user、sys_role 以及 flyway_schema_history 三张表。
  3. flyway_schema_history 表有记录:查询该表,可以看到版本1的执行记录。

验证SQL示例

-- 查看所有表
SHOW TABLES FROM demo_db;

-- 查看Flyway迁移历史
SELECT version, description, script, installed_on, success
FROM flyway_schema_history
ORDER BY installed_rank;

查询结果应类似:

version description script installed_on success
1 init V1__init.sql 2025-01-15 10:23:46 1

3.6 常见问题与排查

🔍 首次启动常见错误及解决方案:
  • 错误: FlywayException: Found non-empty schema(s) but no schema history table.
    解决: 设置 spring.flyway.baseline-on-migrate: true,或在已有数据库上手动执行 flyway baseline。
  • 错误: FlywayException: Validate failed: Migration checksum mismatch for migration version 1
    解决: 不要修改已执行过的脚本。如果确实需要修改,请创建新的迁移脚本(如 V2__fix_init.sql)来修正。
  • 错误: Table 'flyway_schema_history' doesn't exist 且应用启动失败
    解决: 检查数据库连接权限,确保应用账号有 CREATE TABLE 权限。

3.7 本章小结

通过本章的四个步骤,你已经成功在Spring Boot项目中集成了Flyway,并完成了第一次数据库版本化迁移。核心要点回顾:

  • Flyway通过 flyway-core 和数据库专用扩展(如 flyway-mysql)实现自动迁移。
  • 迁移脚本必须放置在 classpath:db/migration 目录下,命名格式为 V{版本}__{描述}.sql。
  • 首次启动时,Flyway会自动创建 flyway_schema_history 元数据表,并执行所有未执行的迁移脚本。
  • 通过日志、数据库表结构和元数据表记录三个维度可以验证迁移是否成功。