IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> SpringBoot+Flyway 自动化数据库脚本版本控制工具 -> 正文阅读

[大数据]SpringBoot+Flyway 自动化数据库脚本版本控制工具

Flyway介绍

为什么要用Flyway

在项目团队开发模式下,代码可以通过SVN或者Git来对代码做版本控制,主要的目的就是为了解决多人开发代码冲突和版本回退的问题。

其实,数据库的变更也需要版本控制,在日常开发中,我们经常会遇到下面的问题:
【1】自己写的SQL忘了在所有环境执行,项目中存在dev/test/prod环境时可能就中间某个阶段出现遗漏。
【2】部分人直接在数据库上执行,部分提交脚本给测试执行,流程方法各种各样,缺少标准。
【3】别人写的SQL我们不能确定是否都在所有环境执行过了;一次系统重新部署,如果有人忘记提交脚本那么就可能导致运行中出现异常。
【3】有人修改了已经执行过的SQL,期望再次执行;
【4】需要新增环境做数据迁移;
【5】每次发版需要手动控制先发DB版本,再发布应用版本;
【6】缺乏自动化,标准化的操作流程
【7】很多项目团队都有SQL管理但是缺少一个简单有效的工具辅助。

参考

不同的开发人员在开发产品特性时,都有可能更新数据库(添加新表,新的约束等)。当开发人员完成工作并提交代码时,代码会被合并到主分支并在测试服务器上执行单元测试与集成测试。我们在哪个环节来执行数据库的更新操作呢?由QA 部门手工执行sql 脚本?或者我们开发一断程序自动执行数据库更新?以什么顺序来执行这些更新脚本?这些问题同样存在于生产环境。
我们的产品部署在不同的客户服务器上,以及很多的测试、联调、实验局、销售环境上。不同的客户和测试环境上都部署着不同版本的产品。当他们需要升级他们的产品到新的版本时,我们不仅需要让他们的管理员可以升级产品到新的版本,同时需要保留他们的已有数据。在升级产品的步骤中,我们清楚地知道客户数据库的当前版本,以及需要在该数据库上执行哪些数据库更新脚本,来更新数据库表结构与数据库中已存在的数据。当升级完成时,数据库表结构及数据应当与升级后的产品版本保持一致。
当升级失败时(比如在升级过程中出现网络连接失败),我们应当支持对失败进行修复。

一个项目单个环境迭代开发的过程中,对于数据库表的修改 DDL,可以通过版本控制工具一起进行控制。只需要在项目上线之前,人工执行新增的 DDL 即可,DDL 的版本是与当前项目迭代版本一致,细致点不至于出现问题。

单个环境版本迭代,数据库的版本号变更流程如下图:
在这里插入图片描述
一般而言,一个项目会同时部署到多套环境当中。随着项目迭代进行,不同环境的项目版本可能并非是同步一致的,甚至因为有的环境需要定制化开发,出现同一个项目多个分支,代码也愈行愈远。

多个环境版本迭代,数据库的版本号变更流程如下图:
在这里插入图片描述
于是在这种情况下,上线服务之前就很痛苦,要想起上线环境的当前表版本是多少,想不起来,就要对比线上库里的表,判断是否执行过了增量的 DDL,每个环境的增量 DDL 都可能是不同的,需要针对每个环境写不同的 DDL,发布时战战兢兢地生怕漏了执行哪个版本的 DDL 导致线上 Bug。

Flyway主要是用来记录每次迭代的版本sql的表结构的变动.在部署某个版本时,能够快找到这个版本对应的sql,避免出现表结构的错误。

Flyway原理简单阐述:开发者将每个版本的 DDL 放到项目中,项目在新环境启动时,会自动创建一张表用于记录 DDL 的版本信息,随后自动执行未执行过的 DDL,同时将执行过的 DDL 信息存入元数据表中。下次再启动时,检测到执行过了,就不会重复执行。

Flyway 大受欢迎是因为它具有简单非常容易安装和学习,同时迁移的方式也很容易被开发者接受。 Flyway 专注于搞数据库迁移、版本控制而并没有其它副作用。专为连续交付而设计。让Flyway在应用程序启动时迁移数据库。

Flyway 的特性

【1】自动升级(自动发现更新项):Flyway 会将任意版本的数据库升级到最新版本。Flyway 可以脱离JVM 环境通过命令行执行,可以通过Ant 脚本执行,通过Maven 脚本执行(这样就可以在集成环境自动执行),并且可以在应用中执行(比如在应用启动时执行)。
【2】规约优于配置:Flyway 有一套默认的规约,所以不需要修改任何配置就可以正常使用。
【3】既支持SQL 脚本,又支持Java 代码:可以使用SQL 脚本执行数据库更新,也可以使用Java 代码来进行一些高级数据升级操作。
【4】高可靠性:在集群环境下进行数据库升级是安全可靠的。
【5】支持清除已存在的库表结构:Flyway 可以清除已存在的库表结构,可以从零开始搭建您的库表结构,并管理您的数据库版本升级工作。
Tips:这个可要慎重,如无特别需求请禁用吧
【6】支持失败修复。新的2.0 版本提供了repair 功能,用于解决数据库更新操作失败问题。

认识

flyway是一个能对数据库变更做版本控制的工具。
GitLab地址:https://github.com/flyway/flyway

flyway提供了以下方式来使用
【1】Command-line
【2】Java API
【3】Maven
【4】Gradle

这里主要说明SpringBoot集成flyway,个人觉得这种集成在项目中更容易容易管理和配置。
引入如下依赖,SpringBoot项目不需要指定版本,已经帮我们做了集成。

        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>

添加如下配置信息

spring:
  flyway:
    # 启用Flyway功能
    enabled: true
    # 禁用Flyway的clean命令,使用clean命令会删除schema下的所有表
    clean-disabled: true
    # 设置Flyway的SQL脚本路径
    locations: classpath:db/migration,classpath:db/callback
    # 设置版本信息控制表名称,默认flyway_schema_history
    table: flyway_schema_history
    # 在执行migrate命令时需要有flyway_schema_history表,通过baseline命令可以生成该表
    baseline-on-migrate: true
    # 指定baseline版本号,低于该版本的SQL脚本在migrate是不会执行
    baseline-version: 0
    # 设置字符编码
    encoding: UTF-8
    # 不允许不按顺序迁移
    out-of-order: false
    # 设置Flyway管控的schema,不设置的话为datasourcel.url中指定的schema
    schemas: flyway
    # 执行migrate时开启校验
    validate-on-migrate: true

然后,在src/main/resources目录下面新建db.migration文件夹,默认情况下,该目录下的.sql文件就算是需要被flyway做版本控制的数据库SQL语句。

测试:在db.migration目录下新建1.0.1目录,并在该目录下创建V1__create_user.sql脚本文件

CREATE TABLE IF NOT EXISTS `T_USER`(
    `USER_ID`          INT(11)           NOT NULL AUTO_INCREMENT,
    `USER_NAME`        VARCHAR(100)      NOT NULL COMMENT '用户姓名',
    `AGE`              INT(3)            NOT NULL COMMENT '年龄',
    `CREATED_TIME`     datetime          NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `UPDATED_TIME`     datetime          NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`USER_ID`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

启动项目,可以看到下面输出的日志,因为使用的是默认的数据库所以新建了flyway数据库,项目中可以指定已存在的数据库,然后并创建了T_USER数据表。
在这里插入图片描述
在这里插入图片描述

实践整理

修改一个已经执行过的V开头的SQL情况

在日常工作开发中,可能会出现无意间修改了原来已经执行的SQL文件,然后提交到了生产环境,那么会不会再次被执行,如果被执行了就会对线上造成影响。
在这里插入图片描述
上面截图中2.2.1/V1__create_user.sql和2.2.2/V2__add_user.sql已经被执行了而且希望只被执行一次,那么现在修改其中的SQL文件(不修改文件的名称)
在这里插入图片描述
其中红色的部分表示的变更的部分,重启项目程序
在这里插入图片描述
重启项目时抛出异常,大致的意思就是检查校验和时无法匹配,即V开头的SQL文件不允许被修改。Applied to database : -1328025572是文件之前的checksum, Resolved locally : -2095201518是变更后计算得到的校验和,不匹配无法通过验证。但是以R开头的是可以重复执行的。
【注意】以上可以看到Flyway通过一种约定的方式对SQL文件进行了一种规则处理,这能够很好的避免重复执行,这也告诉了我们一定要保证flyway_schema_histor数据表的完整性。

测试一个会出现异常的SQL情况

测试一个语法有问题的SQL语句项目启动时检查报错
在这里插入图片描述
不出意外的抛出了异常,但是需要注意的是,虽然项目启动抛出了异常,但是在flyway_schema_history表中却成功插入了一条记录,这条记录的success标识位0,标识失败。
在这里插入图片描述
当我尝试修正SQL并重新执行时,又发生了一个新的问题
FlywayException: Detected failed migration to version:3
根据描述问题肯定发生在2.2.4/V3__student_ddl.sql记录上,最终经过排查定位到了问题所在:
在flyway_schema_history的2.2.4/V3__student_ddl.sql记录发生了一次失败的数据库脚本变更,你必须去解决这个问题,而这个解决不能通过修改SQL重新执行,必须通过flyway的repair 命令去修正该条记录。官方的方式是flyway repair命令去修复,但是这种方式感觉并不适用于实际开发,我总不能通过命令行的方式或者maven插件的方式去链接多个环境的数据库吧,这样的操作不太合适,最简单直接的方式就是删除这一条记录,然后重新启动项目执行。

参考解决方式

【1】手动删除激励

直接删除flyway_schema_history表中迁移失败的记录,然后重新迁移

【2】flyway repair工具命令行

安装Flyway插件,并配置数据库信息,通过命令行:flyway repair 去处理

【3】mvn flyway:repair

在项目中添加maven插件,然后执行mvn flyway:repair。这个需要单独配置数据库连接地址。

【4】自定义实现机制

自定义实现机制,可以实现FlywayMigrationStrategy接口,自定义处理逻辑,这个并没有去深入了解,参考:https://docs.spring.io/spring-boot/docs/1.4.0.RC1/reference/htmlsingle/#howto-execute-flyway-database-migrations-on-startup

【5】设置Flyway Callbacks(推荐)

以上几种方式都是手动处理的,如果想要自动清理失败的迁移记录,可以使用afterMigrateError Flyway callback.
1:在spring配置文件中添加如下映射配置
spring.flyway.locations=classpath:db/migration,classpath:db/callback
2:在resources创建db/callback目录,并添加afterMigrateError__repair.sql脚本文件
3:为了看到效果,先在该脚本下添加如下测试SQL
update flyway_schema_history set success=99 where version=4
4:在db/migration目录下创建V4__student_ddl.sql脚本,并故意设置一个语法错误
5:启动项目,此时项目启动失败,flyway_schema_history插入一条记录,并且success标识被置为99
在这里插入图片描述
6:基于上面的实例,我们就可以在该脚本中添加DELETE FROM flyway_schema_history WHERE success=false; 脚本语句,这表示当发生错误迁移记录时在回调时删除错误迁移记录,以便后面可以修改后重新启动,不需要在手动执行。
7:这里更推荐这一种方式,首先这一种方式是自动化的操作不需要手动修复,其次当发生错误时项目还是启动失败,不存在说问题被隐藏了,而且对于那一条错误数据来说,后续不管是通过手动脚本还是命令行的方式都是删除,最终的结果都是一样的。
8:这里的回调机制不仅仅可以实现这个需求,在其他一些方面也是可以应用的。

文件命名执行规则

Flyway所执行的SQL语句命名需要遵从一定的规范,否则运行的时候flyway会报错。下图是官方给出的命名规范:
在这里插入图片描述
【Prefix】V表示版本标识,以V开头的文件仅会被执行一次,后面跟上"0~9"数字的组合,数字之间可以用“.”或者下划线"_"分割开,然后再以两个下划线分割,其后跟文件名称,最后以.sql结尾。比如,V1.1.1__create_user_ddl.sql、V1.1_2__add_user_dml.sql。U开头的文件标识撤销回滚文件,很尴尬,社区版本貌似不支持这个功能。R开头的文件标识可重复运行的SQL,后面再以两个下划线分割,其后跟文件名称,最后以.sql结尾。。比如,R__truncate_user_dml.sql。可重复执行不是每次在启动的时候都会执行,而是会校验SQL文件是否发生了变更,如果未发生变更是不会执行的。V开头的SQL执行优先级要比R开头的SQL优先级高。
【Version】版本号,对应flyway_schema_history表的version字段。
【Separator】两个下划线,两个下划线,两个下划线,强调下。
【Description】文件描述,描述当前文件实际功能和作用。对应flyway_schema_history表的description字段。
【Suffix】.sql文件

目录的命名不会影响flyway对SQL的识别和运行,可以自行取名和分类。

Flyway 是如何比较两个 SQL 文件的先后顺序呢?它采用 采用左对齐原则, 缺位用 0 代替 。举几个例子:
1.0.1.1 比 1.0.1 版本高。
1.0.10 比 1.0.9.4 版本高。
1.0.10 和 1.0.010 版本号一样高, 每个版本号部分的前导 0 会被忽略。

相关命令

migrate:数据库迁移命令,会根据设置好的SQL脚本直接将数据库表升级至最新版本。
clean:删除数据库中所有的表,千万别在生产环境上使用。
info:打印所有关于数据库迁移的详细信息和状态信息。
validate:验证数据库迁移是否可用。
undo:对数据库迁移进行回滚操作。
baseline:以现有数据库为基准,创建flyway_schema_history
表,大于基准版本的数据库迁移才会被应用。
repair:修复flyway_schema_history表。

JPA Buddy自动生成差异SQL

JPA Buddy一般用作自动生成 JPA 实体类,但是它的功能不仅仅如此,它还集成了Flyway,可以帮助我们自动生成版本变更SQL语句。在IDEA上安装 JPA Buddy插件,安装完成之后还需要添加下jpa的依赖才会展示控制面板,这里只是引入该依赖,不是代表需要使用JPA。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

控制面板如下
在这里插入图片描述
勾选+符号
在这里插入图片描述
如上图所示,其中Empty Versioned Migration、Diff Versioned Migration、Init Schema Migration、SQL Call Back都是和Flyway关联的功能。本次演示下Diff Versioned Migration这也是我最感兴趣的功能,即对比两个数据库的版本差异,比如DEV和TEST的差异,然后自动生成差异SQL,然后直接提交给测试项目即可。
在上面配置两个环境的数据库,然后选中Diff Versioned Migration,这里需要等待一段时间,数据表较多,如下图所示,该工具自动帮助我们生成了DML和DDL语句,并且自动将这些代码合并在一个文件,还直接放到了db/migration目录下,非常的方便,这样我们后续直接运行项目即可
在这里插入图片描述
在这里插入图片描述

问题整理

Detected resolved migration not applied to database

这个问题是因为Flyway所识别到的当前版本记录和数据库保存的最新版本记录次序颠倒、发生冲突又或者存在失败迁移记录,解决方式参考
1:修改当前sql文件名称
2:删除或修改数据库中的最大的版本记录
3:flyway Repair

参考案例:本篇博文(2)测试一个会出现异常的SQL情况模块

flyway的配置清单

flyway.baseline-description对执行迁移时基准版本的描述.
flyway.baseline-on-migrate当迁移时发现目标schema非空,而且带有没有元数据的表时,是否自动执行基准迁移,默认false.
flyway.baseline-version开始执行基准迁移时对现有的schema的版本打标签,默认值为1.
flyway.check-location检查迁移脚本的位置是否存在,默认false.
flyway.clean-on-validation-error当发现校验错误时是否自动调用clean,默认false.
flyway.enabled是否开启flywary,默认true.
flyway.encoding设置迁移时的编码,默认UTF-8.
flyway.ignore-failed-future-migration当读取元数据表时是否忽略错误的迁移,默认false.
flyway.init-sqls当初始化好连接时要执行的SQL.
flyway.locations迁移脚本的位置,默认db/migration.
flyway.out-of-order是否允许无序的迁移,默认false.
flyway.password目标数据库的密码.
flyway.placeholder-prefix设置每个placeholder的前缀,默认${.
flyway.placeholder-replacementplaceholders是否要被替换,默认true.
flyway.placeholder-suffix设置每个placeholder的后缀,默认}.
flyway.placeholders.[placeholder name]设置placeholder的value
flyway.schemas设定需要flywary迁移的schema,大小写敏感,默认为连接默认的schema.
flyway.sql-migration-prefix迁移文件的前缀,默认为V.
flyway.sql-migration-separator迁移脚本的文件名分隔符,默认__
flyway.sql-migration-suffix迁移脚本的后缀,默认为.sql
flyway.tableflyway使用的元数据表名,默认为schema_version
flyway.target迁移时使用的目标版本,默认为latest version
flyway.url迁移时使用的JDBC URL,如果没有指定的话,将使用配置的主数据源
flyway.user迁移数据库的用户名
flyway.validate-on-migrate迁移时是否校验,默认为true

小结

【1】SQL语句命名需要遵从一定的规范,以V或者R开头,然后是双下划线…;
【2】尽量不要修改已经执行过的SQL,即便是R开头的可反复执行的SQL,它们会不利于数据迁移;
【3】生产务必禁 spring.flyway.cleanDisabled=false
【4】spring.flyway.outOfOrder配置,个人使用中看到很多处理flyway迁移失败异常时使用该方式,但是这里还是不建议放开该配置,严格管理还是有必要的,保持out-of-order: false不允许不按顺序迁移。
【5】撤消迁移(例如删除先前迁移中添加的列)可能会非常棘手,并且通常需要开发人员创建数据备份。
【6】项目中也可以根据需要创建一个初始版本,这个初始版本可以将现有数据库通过某些工具导出SQL脚本放上去,作为一个基础版本。
【7】spring-boot也集成很多flyway的功能,包括自定义策略配置、回调接口实现等等,可以通过这个进行适当的扩展。
【8】总的来看,通过flyway来管理和执行SQL,在一定程度上保证SQL脚本的版本化和规范化,同时通过该工具也进一步提供了更加自动化的处理方式。

参考

Capital One 使用Flyway进行数据库迁移

https://jiagoushi.pro/capital-one-database-migrations-flyway

在大型项目中使用Flyway进行数据库迁移
https://jiagoushi.pro/database-migration-flyway-large-project

Database Migrations with Flyway
https://www.baeldung.com/database-migrations-with-flyway#generate-versioned-migrations-in-intellij-idea

官网:https://flywaydb.org/documentation/

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-06-23 00:55:58  更:2022-06-23 00:57:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:29:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码