目录java
Flyway的定位:数据库的版本控制。linux
用一种简单、干净的方案,帮助用户完成数据库迁移的工做。使用Flyway,用户能够从任意一个数据库版本迁移到最新版本,简单并且有效。android
支持多个平台:windows、ios、linux、docker、java、androidios
2018年度,产品被下载1千万屡次:spring
开源:sql
支持多种使用方式:docker
基于命令行模式,用户从官网下载工具包,进行一些必要的配置,就能够经过命令行使用其功能。数据库
基于Java API,用户能够将Flyway提供的第三方包加入classpath,经过Flyway提供的API来使用其功能。windows
基于Maven或Gradle,用户能够经过配置插件,运行mvn或gradle命令来使用其功能。api
支持多种数据库:
被spring-boot集成:
官方文档简洁,以我这样蹩脚的英语水平,也很容易理解。
P.S. 开源版本支持大部分经常使用的功能,Flyway还有商业版本,会支持一些额外的功能。
这一节主要介绍Flyway是如何工做的,也能够理解为flyway的数据库升级方案。
Flyway能够对数据库进行升级,从任意一个版本升级到最新的版本。可是升级的依据是用户本身编写的sql脚本,用户本身决定每个版本的升级内容。
Flyway不限定脚本里面的内容,可是对脚本文件的名称有必定的要求:
版本号可使用小版本,如V1.1。
具体要求:
使用Flyway升级,flyway会自动建立一张历史记录表:flyway_schema_history。
这张表记录了每一次升级的记录,包括已经执行了哪些脚本,脚本的文件名,内容校验和,执行的时间和结果:
flyway在升级数据库的时候,会检查已经执行过的版本对应的脚本是否发生变化,包括脚本文件名,以及脚本内容。若是flyway检测到发生了变化,则抛出错误,并终止升级。
若是已经执行过的脚本没有发生变化,flyway会跳过这些脚本,依次执行后续版本的脚本,并在记录表中插入对应的升级记录。
因此,flyway老是幂等的,并且能够支持跨版本的升级。
若是你好奇,flyway如何检查脚本文件的内容是否有修改。你能够注意如下记录表中有一个字段checksum,它记录了脚本文件的校验和。flyway经过比对文件的校验和来检测文件的内容是否变动。
使用上面的方式,升级一个空的数据库,或者在一直使用flyway升级方案的数据库上进行升级,都不会又问题。可是,若是在已有的数据库引入flyway,就须要一些额外的工做。
flyway检测数据库中是否有历史记录表,没有则表明是第一次升级。此时,flyway要求数据库是空的,并拒绝对数据库进行升级。
你能够设置baseline-on-migrate参数为true,flyway会自动将当前的数据库记录为V1版本,而后执行升级脚本。这也表示用户所准备的脚本中,V1版本的脚本会被跳过,只有V1以后的版本才会被执行。
下文在介绍Maven客户端的时候,会介绍另外一种方案,实如今已有数据库中第一次引入flyway。
用户能够在官网下载适合本身平台的工具包,进行相关配置以后,就能够经过命令行的方式使用Flyway。
这一块只是在官网上看到其介绍,本人并无尝试,我直接选择了后面的方案。
这种方式能够代替命令行的方式,由于咱们项目中就使用maven,因此我更倾向于使用这种方式。
以Maven为例,在pom文件中进行必要的配置,包括插件及插件所须要的一些数据库链接信息,就能够经过运行插件来使用其功能。
<?xml version="1.0" encoding="UTF-8"?> <project ...> <properties> <flyway.user>postgres</flyway.user> <flyway.password>postgres</flyway.password> <flyway.url>jdbc:postgresql://localhost:5432/test?currentSchema=demo_flyway</flyway.url> <flyway.driver>org.postgresql.Driver</flyway.driver> </properties> <dependencies> ... <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> ... </dependencies> <build> <plugins> <plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
maven插件所支持的命令:
使用maven命令执行插件,默认在classpath:/db/migration
目录搜索脚本,若是该目录不存在,命令将被忽略。
全部的命令,以以下的格式执行:
mvn flyway:{flyway-command}
mvn flyway:migrate
这个命令会搜索默认的脚本目录,检测并根据结果选择执行升级脚本。
mvn flyway:clean
这个命令会清除指定schema下全部的对象,包括table、view、triggers...,让schema变成空的状态。
mvn flyway:info
这个命令显示指定schema的升级状态,当前的数据库的版本信息。
mvn flyway:validate
这个命令用于校验,范围包括已升级的脚本是否更名,已升级的脚本内容是否修改。全部针对已升级的脚本进行的改动都会致使校验失败。
执行migrate会自动进行校验,若是失败将不会作任何的migrate。
flyway但愿用户提供的脚本是稳定的,以避免形成额外的复杂性和混乱。
mvn flyway:baseline
若是用户从一个已有的数据库导出脚本,做为flyway的升级脚本。已存在的数据库是不须要升级的。
baseline用于将当前数据库标记为baseline,并记录version为1。这表示用户继续执行migrate命令时,会自动跳过V1版本对应的脚本。
而对于空的数据库,由于没有执行baseline,因此能够正常的执行V1版本对应的脚本。
P.S. 手动修改flyway自动生成的baseline记录,将版本号改成其余的版本号,将自动跳过该版本及更早的版本。
Flyway提供了基于Java的API包,用户能够将API包引入maven依赖,直接经过调用其API来执行相关命令。
Spring-Boot集成了Flyway,只要把API包加入classpath,spring-boot在启动应用时会去指定的目录查找脚本文件,并根据必定的策略选择或忽略执行。
使用Spring-Boot,用户没必要再显式的编写代码调用API,只须要将脚本文件放在约定的目录,或者告诉Spring-Boot你把脚本文件放在哪里了。
若是用户须要实现很是灵活的迁移,Spring-Boot默认的方案没法知足,也能够尝试寻找本身编码调用API的方案。
如下内容介绍基于Spring-Boot + Maven的集成方案:
<?xml version="1.0" encoding="UTF-8"?> <project ...> ... <dependencies> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> ... </dependencies> ... </project>
flyway-core即为咱们所说的API包,除此以外,还要引入postgresql驱动包和spring-boot-starter-jdbc。
按照常规的方式,在application.yml文件中配置spring.datasource系列:
spring: datasource: url: jdbc:postgresql://localhost:5432/test?currentSchema=demo_flyway driver-class-name: org.postgresql.Driver username: postgres password: postgres
spring为flyway准备了专属的数据源配置,可是在默认的状况下,能够直接使用spring.datasource的配置。
用户能够将脚本放在约定的位置:classpath:/db/migration
,或者配置一个自定义的位置:
若是用户没有特意设置脚本的位置,则应该在/db/migration
建立脚本。不然,在对应的位置建立脚本。
咱们是在中途尝试使用flyway,因此开发环境会有一个已存在的数据库。咱们须要从开发环境中导出数据库脚本,并对开发环境数据库进行baseline标记。导出的脚本可用于新环境的部署。
若是咱们已经有了生产环境,并且生产环境和开发环境的数据库已经有了较大的差别。暂时能够想到的方案大概有2个方案:
方案一:
在生产环境备份数据库,而后建立一个全新的数据库,手动将备份库里的数据导入到新的数据库。
方案二:
基于生产环境的数据库,建立V1版本的脚本;基于开发库相对于生产库的变动,建立V2版本的脚本。在开发环境baseline,而后修改版本记录,改成2。在生产环境中baseline,而后migrate使其升级到2。
方案一,须要更多的人工介入,可是比较稳妥;方案二,难点在于溯源出正确的差别,编制V2脚本。