一文了解数据库迁移工具—Flyway
Flyway
是一个数据库版本管理工具,可以非常简单的将数据库的schema
从一个版本迁移到另外一个版本,并且支持MySql,Oracle,Postgre
等多种关系型数据库
What is Flyway
Flyway
主要就是通过迁移(Migration
)来对数据库进行版本的控制,对于Flyway
而言在数据库上的所有操作都可以称之为迁移;Flyway
有两种迁移方式:版本化迁移(Versioned Migration
)和可重复的迁移(Repeatable Migration
)
Versioned Migrations
Flyway
的版本化迁移有两种形式:
- 常规的版本升级(
Regular
) - 版本撤销回退(
Undo
)
版本化迁移包含一个版本,描述和checksum
;版本是唯一的,描述是用来告诉别人这个版本执行了什么操作,校验和(checksum)
用于检查当前执行脚本是否有变动,如果有变动那么就会执行失败,因为版本化迁移中所有的sql
脚本只会执行一次
Repeatable Migration
可重复迁移包含一个描述(description
)和一个校验和(checksum
),但没有版本;在可重复迁移中,只要它的校验和(checksum
)发生变化就会执行,校验和就是脚本文件的内容变化
在单次的迁移操作中,如果同时存在Versioned Migration
和Repeatable Migration
,那么优先按版本顺序执行Versioned Migration
等所有的版本迁移执行之后,才会执行Repeatable Migration
Migration Format
默认的情况下,版本化迁移和可重复迁移可以用SQL
或Java
编写,并且可以包含多个语句;目前Flyway
也支持用脚本语言进行迁移,目前支持.ps1
, .bat
, .cmd
, .sh
, .bash
, .py
等脚本
SQL-Based Migration
常用的迁移方式就是基于sql
的迁移,因为这很容易就能够掌握,并且不需要学习其他的知识,而且可以灵活的满足各种需求
基于SQL
迁移的文件有如下的命名规则:
文件名由如下几部分组成:
- 前缀:
V
表示版本化,U
表示撤销回退,R
表示可重复迁移 - 版本:版本一般为数字,多个数字之间用点分割,比如:
V1.1,V1
等 - 分隔符:
__
双下划线 - 描述:表示当前脚本执行的操作类型
- 后缀:
.sql
上面的这些组成部分都是可以进行配置的,如果想配置可以参考这个文档
Java-Based Migration
基于java
迁移是为了更好的满足不易于sql
执行的迁移操作,比如:
- 二进制数据的更改
- 批量数据的更改
基于java
迁移的脚本文件和基于SQL
迁移的脚本文件有一些不同:
基于java
的迁移没有了后缀,其他的都是类似的,具体可参考!Flyway文档
Flyway
会自动的在文件系统和java classpath
中查找迁移文件;为了追踪迁移的状态Flyway
会在数据库的当前schema
中添加表flyway_schema_history
对每次迁移进行记录
Why Flyway
为什么需要Flyway
呢?下面我们通过一个例子来简单的说明我们为什么需要Flyway
,以及Flyway
到底能帮我们解决什么问题
假设,现在我们有一个项目:Shiny
,该项目连接了一个数据库:Shiny DB
,它们作为一个整体进行交付;用一个简单的示意图表示为:
在项目的开发周期中,会同时有多个开发者参与到项目,项目完成之后还需要进行持续集成,测试,然后上线到生产,整个流程的示意图可以简单的表示为如下这样:
在整个交付的过程中:
- 我们有代码版本控制工具
git
,保证交付的代码和本地一致 - 我们有
docker
可以打包应用环境,依赖保证和我们本地有相同的构建环境 - 并且还有
DockerHub
之类的镜像仓库来管理镜像版本
但数据库呢?如何才能保证本地执行的脚本和生产的一致呢
现在很多项目还是依赖手动执行脚本,但这会引起一些问题:
- 当前机器上的应用对应的数据库处在什么状态(也就是,执行了那些
sql
脚本,又有那些没执行) - 当前的脚本是应该执行还是不应该执行呢
- 在生产中快速修复的问题是否在后面的测试中应用了呢
- 如何去部署一个新的数据库实例呢
其实大多数的时候,我们根本不知道,因为通常一个应用会有很多人操作,但是根本没人会记录当前数据库所处的状态,以致于一点改动都需要花很长的时间去检查,部署
Flyway
作为数据迁移工具很好的解决了这种混乱的状态,它可以让你:
- 很快的从头创建一个数据库实例
- 清楚的知道当前数据库所处的状态
- 以一种确定的方式从当前一个版本迁移到一个新的版本
SpringBoot With Flyway
在SpringBoot
中引入Flyway
是非常方便的,首先是添加Flyway
和相关的依赖;如果使用Maven
可以在pom.xml
文件中添加如下配置:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
如果使用Gradle
可以在build.gradle
中添加如下的依赖配置
compile('org.flywaydb:flyway-core')
compile('org.springframework.boot:spring-boot-starter-jdbc')
compile('org.springframework.boot:spring-boot-starter-web')
compile('mysql:mysql-connector-java')
接下来就是在application.properties
中添加数据库和Flyway
相关的配置
spring.application.name = flywayapp
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/USERSERVICE?autoreconnect=true
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.testOnBorrow = true
spring.datasource.testWhileIdle = true
spring.datasource.timeBetweenEvictionRunsMillis = 60000
spring.datasource.minEvictableIdleTimeMillis = 30000
spring.datasource.validationQuery = SELECT 1
spring.datasource.max-active = 15
spring.datasource.max-idle = 10
spring.datasource.max-wait = 8000
flyway.baselineOnMigrate= false
flyway.outOfOrder= false
flyway
相关的配置可以在官方文档中查看
因为flyway
默认是在resource/db/migration
目录下查找脚本文件,所以我们在这个目录下创建脚本文件进行数据库的迁移,命名为:V1__Initial.sql
,添加如下的sql
语句
CREATE TABLE USERS (ID INT AUTO_INCREMENT PRIMARY KEY, USERID VARCHAR(45));
INSERT INTO USERS (ID, USERID) VALUES (1, 'tutorialspoint.com');
在SpringBoot
中配置了Datasource
之后,当程序启动的之后就会自动注入到Flyway
中,所以完成如上的配置之后就可以启动程序进行验证了
参考连接:
转载自:https://juejin.cn/post/7140915466729422862