数据库版本管理工具 Flyway 使用
Posted 清茶_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库版本管理工具 Flyway 使用相关的知识,希望对你有一定的参考价值。
目录
一、简介
Flyway是一款开源的数据库版本管理工具,使用简单,应用无侵入。与 Liquibase 相比,由于 Flyway 面向sql,因此更直观清晰,对于我们来说,轻便的 Flyway 是一个更好的选择,两者相比一言以蔽之:
- 面向 SQL,选择 Flyway
- 不面向 SQL,选择 Liquibase
二、核心概念
1、Schema History Table
Flyway 对数据库进行版本控制的方式,是在指定数据库中创建一张表,即 Schema History Table(默认为 flyway_schema_history),记录由 Flyway 所执行的 sql 脚本状态。
表中字段解释:
- installed_rank:执行序号
- version:版本
- script:sql脚本文件
- checksum:类似文件md5值,用来检查 migration 在执行过后是否发生了变化,如果发生了变化,会导致这个版本以及后续版本的 migration 无法执行
- success:是否执行成功,1成功,0失败
2、Migration
Flyway 将每一个数据库脚本称之为:migration,migration 可以是 SQL 文件,也可以是 Java 类,默认的查找 migration 的路径为 classpath:db/migration,对应 SQL 文件可放置在 src/main/resources/db/migration 下,Java 类可放置在 src/main/java/db/migration 下。flyway 支持三种类型的migration:
- Versioned migrations:最常用的 migration,可以简单的理解为数据库升级脚本
- Undo migrations:数据库版本回退脚本,可为对应版本的常规 versioned migration 进行回退操作,此功能为收费功能,社区版无法使用
- Repeatable migrations:可重复执行的 migration,例如create or replace脚本,会在所有的 versioned migration 都执行过后再进行执行,即当脚本 checksum 改变时重新执行
所有的 migration 都需要遵守命名规范:
3、Versioned migrations
这里单独介绍下 Versioned migrations,关于命名规范,需要一个大写的 V 作为版本的前缀标志,然后在后面紧跟着一个数字作为版本号(版本号可以是数字加.的形式),这个就是 Flyway 进行追踪的依据,在版本号后面需要下划线作为分隔符用来分割版本号和说明(这里特别需要注意的是分隔符是两个下划线)。
其中版本号必须全局(一个 Schema History Table 里)唯一,且默认情况下(可通过参数调整)版本号只能增加,不能在已经执行了高版本的 migration 之后再执行低版本的 migration。
三、集成 SpringBoot
1、pom文件中引入依赖
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>6.4.4</version>
</dependency>
2、application.yml配置
spring:
flyway:
# 是否启用flyway
enabled: true
# 编码格式,默认UTF-8
encoding: UTF-8
# 迁移sql脚本文件存放路径,默认db/migration
locations: classpath:db/migration
# 迁移sql脚本文件名称的前缀,默认V
sql-migration-prefix: V
# 迁移sql脚本文件名称的分隔符,默认2个下划线__
sql-migration-separator: __
# 迁移sql脚本文件名称的后缀
sql-migration-suffixes: .sql
# 迁移时是否进行校验,默认true
validate-on-migrate: true
# 当迁移发现数据库非空且不存在元数据表时,自动执行基准迁移,新建schema_version表
baseline-on-migrate: true
3、sql 脚本编写
在 src/main/resources 下新建 /db/migration 文件夹,并创建 sql 脚本文件:
上面的配置已经设置了 baseline-on-migrate 为 true(默认 false),即已经告诉 Flyway 执行 migration 的时候是存在基线的,这样就不会报出数据库表不存在的错了。因此不管你的数据库是否非空,都能顺利运行,唯一的区别是第一个 sql 脚本文件的执行
拿上面这张图的 V1.0__init_database.sql 脚本来说,如果数据库为空,则默认会执行;反之则会把它作为基线,跳过执行下一个版本
数据库非空情况下 flyway_schema_history 表记录:
数据库为空情况下 flyway_schema_history 表记录:
四、初始化数据库
SpringBoot 集成完 Flyway 之后,数据库的创建同样需要作为程序启动即执行,否则项目复用时仍然需要先创建数据库再启动程序,不是很智能,部分代码如下:
public void initDataBase()
try
String databaseName = properties.getDatabaseName();
if (StringUtils.isEmpty(databaseName))
databaseName = JdbcUrlUtils.findDatabaseName(datasourceUrl);
log.debug("尝试获取spring.datasource.url中的数据库名称...url:,name:", datasourceUrl, databaseName);
String jdbcUrlTmp = datasourceUrl.replace(SLASH+databaseName,BLANK);
SingleConnectionDataSource dataSourceTmp = new SingleConnectionDataSource(jdbcUrlTmp,username,password,true);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceTmp);
String executeSql = String.format(properties.getCreateSchemaSql(), databaseName);
jdbcTemplate.execute(executeSql);
log.info("执行初始化库的sql,sql:", executeSql);
catch (Exception e)
log.error("校验数据库失败!", e);
在抽象初始化数据库这部分代码作为组件时,有一点需要注意,如果你的项目有使用 Mybatis-plus 框架,不建议采用自动配置的方式初始化bean,会出现 mp 的自动配置类执行顺序始终比自定义配置类快,可以采用 InitializingBean 和 BeanPostProcessor
五、注意事项
1、脚本文件如果已经执行过,便不要在进行任何更改,如果需要修改请通过新增一个新的 sql 脚本文件来达成;否则修改一个已经执行过的脚本,会导致 Flyway 校验失败(还原该脚本可以解决)
2、sql 脚本有错误,执行失败后进行修改,再次执行报错,理由同1,此时需要删除 flyway_schema_history 中对应版本的约束然后重新执行
3、增量脚本里的 sql 尽量保证可以多次执行
Flyway 数据库迁移工具信息选项不打印版本号
【中文标题】Flyway 数据库迁移工具信息选项不打印版本号【英文标题】:Flyway database migration tool info option not printing the version number 【发布时间】:2018-01-18 02:41:38 【问题描述】:我们已将 flyway 与 Redshift 集成,我们将其用作简单的 java 主程序来运行我们所有的模式迁移。我们还使用 info 命令打印数据库的当前版本,但是该命令成功运行或至少看起来运行但不打印版本号。 我们有 4.2 版的 flyway jar。我们可能缺少什么?谢谢
【问题讨论】:
【参考方案1】:要手动重新创建 info command line option 在 java 代码中所做的事情,您可以复制其实现所做的事情(来自 source):
MigrationInfoDumper.dumpToAsciiTable(flyway.info().all())
文档中的一个示例如下所示:
+-------------+------------------------+---------------------+---------+
| Version | Description | Installed on | State |
+-------------+------------------------+---------------------+---------+
| 1 | Initial structure | | Pending |
| 1.1 | Populate table | | Pending |
| 1.3 | And his brother | | Pending |
+-------------+------------------------+---------------------+---------+
【讨论】:
我正在从我的 java 主程序运行 flyway 的 info 命令,我希望从元数据表中得到输出,但我没有看到任何结果或任何错误消息。 感谢您的澄清;您正在通过 Java API 运行。要查看版本信息,请尝试模拟命令行 info 命令的作用(来自 source):MigrationInfoDumper.dumpToAsciiTable(flyway.info().all())
感谢 Harnish Carpenter。你上面的建议奏效了!!再次感谢您对此提供的帮助。
@LakshmiRaju,我已经根据我们的 cmets 更新了我的答案。如果可行,请接受。以上是关于数据库版本管理工具 Flyway 使用的主要内容,如果未能解决你的问题,请参考以下文章
Flyway详解以及Springboot集成Flyway, 数据库脚本版本管理
企业分布式微服务云SpringCloud SpringBoot mybatis (十五)Spring Boot中使用Flyway来管理数据库版本