Flyway 数据库版本管理 | 专业解决方案

前言

目前很多公司都是通过人工去维护、同步数据库脚本,但经常会遇到疏忽而遗漏的情况,同时也是非常费力耗时

比如说我们在开发环境对某个表新增了一个字段,而提交测试时却忘了提交该 SQL 脚本,导致出现 bug 而测试中断,从而影响开发、测试的工作效率

我们可以使用 Git/ SVN 等工具进行代码的版本控制,同时,数据库也有对应的版本控制工具,可以记录数据库的变化记录

Flyway 是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway 可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations 可以写成 SQL 脚本,也可以写在 Java 代码中,不仅支持 Command Line 和 Java API,还支持 Build 构建工具和 Spring Boot 等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等

官网首页:Homepage - Flyway (flywaydb.org)

特性

普通 SQL:纯 SQL 脚本(包括占位符替换)没有专有的 XML 格式,没有锁定

无限制:使用 Java 代码来进行一些高级数据操作

零依赖:只需运行在 Java6(及以上)和数据库所需的 JDBC 驱动

约定优于配置:迁移时,自动查找系统文件和类路径中的 SQL 文件或 Java 类

高可靠性:在集群环境下进行数据库升级是安全可靠的

云支持:完全支持 Microsoft SQL Azure, Google Cloud SQL & App Engine、Heroku Postgres 和 Amazon RDS

自动迁移:使用 Flyway 提供的 API,让应用启动和迁移同时工作

快速失败:损坏的数据库或失败的迁移可以防止应用程序启动

数据库清理:在一个数据库中删除所有的表、视图、触发器,而不是删除数据库本身

原理

当 Flyway 连接数据库中的 schema 后,会先检查是否已存在 flyway_schema_history 表,如果没有则创建。该表用于跟踪数据库的状态,如数据迁移的版本,迁移成功状态等信息

flyway_schema_history 存在后,Flyway 会扫描文件系统或应用中的 classpath 目录的数据迁移文件,然后根据它们的版本号进行按序迁移,如下图:

由于 flyway_schema_history 表中记录了迁移的版本号,如果文件的版本号小于或等于标记为当前版本的版本号,则忽略它们不执行

实战

数据库:MySQL 8.0
官方文档:Quickstart - API - Flyway - Product Documentation (red-gate.com)

Maven

首先新建 Maven 项目

添加依赖

xml 复制代码
        <!-- flyway -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>

创建迁移

首先我们需要创建迁移文件 src/main/resources/db/migration

然后配置数据库迁移文件,实施第一次迁移 src/main/resources/db/migration/V1__Create_person_table.sql

注意:V1 后面是两个下划线,必须是这样的格式

sql 复制代码
create table PERSON
(
    ID   int          not null,
    NAME varchar(100) not null
);

然后配置主启动函数

java 复制代码
public class App {
    public static void main(String[] args) {

        String url = "jdbc:mysql://127.0.0.1:3306/flyway?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8";
        String user = "root";
        String password = "111111";
        Flyway flyway = Flyway.configure().dataSource(url, user, password).load();

        // 创建 flyway_schema_history 表
//		flyway.baseline();

        // 删除 flyway_schema_history 表中失败的记录
//		flyway.repair();

        // 检查 sql 文件
//		flyway.validate();

        // 执行数据迁移
        flyway.migrate();

        // 删除当前 schema 下所有表
//		flyway.clean();

    }

}

执行程序

执行 App 程序

注:我们需要提前创建空数据库 flyway,如果 flyway 不是项目初期引入,后面会给出解决方案

然后我们可以看到现在已经创建了 flyway_schema_history 表和 PERSON 表,数据已经成功迁移到指定数据库中

现在如果系统升级,需要做数据迁移时,我们只需在 db/migration 目录下再放置新版本的 sql 文件即可

现在我们配置第二次迁移 ,创建文件 src/main/resources/db/migration/V2__Add_people.sql

sql 复制代码
insert into PERSON (ID, NAME)
values (1, 'Axel');
insert into PERSON (ID, NAME)
values (2, 'Mr. Foo');
insert into PERSON (ID, NAME)
values (3, 'Ms. Bar');

然后执行 App ,就可以看到如下执行成功

SpringBoot

下面整合 flyway 到 springboot

添加依赖

xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>

配置 application.yml

yml 复制代码
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/flyway?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 111111
  flyway:
    enabled: true
    # 禁止清理数据库表
    clean-disabled: true
    # 如果数据库不是空表,需要设置成 true,否则启动报错
    baseline-on-migrate: true
    # 与 baseline-on-migrate: true 搭配使用
    baseline-version: 0
    # 不配置默认为 db/migration 目录
    locations:
      - classpath:db/migration/mysql

如果 flyway 不是项目初期引入,而是在数据库已有表的情况下引入时必须设置 baseline-on-migrate: true(此时没有配置 baseline-version: 0),设置该配置启动项目后,flyway 就会在数据库中创建 flyway_schema_history 表,并且会往该表中插入一条 version = 1 的建表记录,如果迁移数据有 V1__ 开头的文件,扫描文件会忽略该文件不执行迁移,进而可能引发其他迁移数据出错的问题

因为没有执行 V1__ 开头的文件,那么库中就不创建 PERSON 表,在迁移 V2 插入数据时就会插入失败

所以出现如上问题后,我们可以先删除flyway_schema_history 表,然后配置文件中设置 baseline-version: 0 即可,或者说修改数据迁移文件名称也是可行的

其他问题

版本问题

SpringBoot 2.4.4 集成 flyway 版本 7.1.1 (Oracle12.1.0.2 标准版可以执行,企业版不行)

SpringBoot 2.6.0 集成 flyway 版本 8.0.4 (Oracle12.1.0.2 都可以执行)

SQL 脚本命名规范

Prefix+Version+Separator+Description+Suffix

Prefix 前缀:V 代表版本迁移,U 代表撤销迁移,R 代表可重复迁移

Version 版本号:版本号通常 . 和整数组成

Separator 分隔符:固定由两个下划线 __ 组成

Description 描述:由下划线分隔的单词组成,用于描述本次迁移的目的

Suffix 后缀:如果是 SQL 文件那么固定由 .sql 组成,如果是基于 Java 类则默认不需要后缀

参考链接

本文由博客一文多发平台 OpenWrite 发布!

相关推荐
咖啡教室3 小时前
日常开发中常用的git操作命令和使用技巧
git
数据智能老司机4 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机5 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
松果猿5 小时前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
无名之逆5 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
s9123601015 小时前
rust 同时处理多个异步任务
java·数据库·rust
数据智能老司机5 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
hzulwy6 小时前
Redis常用的数据结构及其使用场景
数据库·redis
程序猿熊跃晖6 小时前
解决 MyBatis-Plus 中 `update.setProcInsId(null)` 不生效的问题
数据库·tomcat·mybatis
Three~stone7 小时前
MySQL学习集--DDL
数据库·sql·学习