Flyway进行数据库版本管理
Flyway 说明
官方文档:Documentation
参考博客:Flyway客户端使用
命令行
Flyway支持命令行操作,需要下载对应系统的命令行客户端。下载地址Command-line tool
命令行格式:
flyway [options] command
支持的命令列表
migrate
: Migrates the database
clean
: Drops all objects in the configured schemas
info
: Prints the details and status information about all the migrations
validate
: Validates the applied migrations against the ones available on the classpath
baseline
: Baselines an existing database, excluding all migrations up to and including baselineVersion
repair
: Repairs the schema history table
命令详解:
命令一:Migrate
Migrate是指把数据库Schema迁移到最新版本,是Flyway工作流的核心功能,Flyway在Migrate时会检查Metadata(元数据)表,如果不存在会创建Metadata表,Metadata表主要用于记录版本变更历史以及Checksum之类的。
结合客户端理解:
执行sql文件夹中未执行的sql,将sql版本更到最新。
命令二:Clean
Clean相对比较容易理解,即清除掉对应数据库Schema中的所有对象,包括表结构,视图,存储过程,函数以及所有的数据等都会被清除。 Clean操作在开发和测试阶段是非常有用的,它能够帮助快速有效地更新和重新生成数据库表结构,
特别注意:在生产环境上禁止使用该命令,使用不当将删除所有生产数据表!
结合客户端理解:
删除指定数据库里头的所有表。
命令三:Info
Info用于打印所有Migrations的详细和状态信息,其实也是通过Metadata表和Migrations完成的,下图很好地示意了Info打印出来的信息。 Info能够帮助快速定位当前的数据库版本,以及查看执行成功和失败的Migrations。
结合客户端理解:
输入所有flyway执行过的信息。
命令四:Validate
Validate是指验证已经Apply的Migrations是否有变更,Flyway是默认是开启验证的。 Validate原理是对比Metadata表与本地Migrations的Checksum值,如果值相同则验证通过,否则验证失败,从而可以防止对已经Apply到数据库的本地Migrations的无意修改。
结合客户端理解:
校验schema_version表的执行情况
命令五:Baseline
Baseline针对已经存在Schema结构的数据库的一种解决方案,即实现在非空数据库中新建Metadata表,并把Migrations应用到该数据库。 Baseline可以应用到特定的版本,这样在已有表结构的数据库中也可以实现添加Metadata表,从而利用Flyway进行新Migrations的管理了。
结合客户端理解:
设定schema_version表的基线执行版本。
命令六:Repair
Repair操作能够修复Metadata表,该操作在Metadata表出现错误时是非常有用的。 Repair会修复Metadata表的错误,通常有两种用途: 移除失败的Migration记录,该问题只是针对不支持DDL事务的数据库。 重新调整已经应用的Migratons的Checksums值,比如:某个Migratinon已经被应用,但本地进行了修改,又期望重新应用并调整Checksum值,不过尽量不要这样操作,否则可能造成其它环境失败。
结合客户端理解:
删除schema_version表里头失败的记录。
SQL脚本
Java项目中:
- SQL脚本文件默认位置是项目的源文件夹下的db/migration 目录。
- SQL脚本文件及Java代码类名必须遵循以下命名规则:
V<version>[_<SEQ>][__description]
。版本号的数字间以小数点.
或下划线_
分隔开,版本号与描述间以连续的两个下划线__
分隔开。如V1_1_0__Update.sql
。Java类名规约不允许存在小数点,所以Java类名中版本号的数字间只能以下划线进行分隔。
命令行模式:
- SQL脚本默认存放在flyway安装目录下的sql目录下。
配置
以使用Flyway的命令行工具为例。安装命令行工具后,运行时Flyway会根据以下路径来寻找配置文件。
安装目录/conf/flyway.conf
用户目录/flyway.conf
当前目录/flyway.conf
- 直接在命令行使用
-configFile=myfile.conf
来指定文件,例如:
flyway -configFiles=path/to/myAlternativeConfig.conf migrate
配置内容:
flyway.url=
flyway.driver=com.mysql.jdbc.Driver
flyway.user=
flyway.password=
#假如已经执行了版本1和版本3,如果增加了一个版本2,下面这个选项将会允许执行版本2的脚本
flyway.outOfOrder=true
# 修改SQL文件的目录,默认为安装目录下sql目录
# flyway.locations=
状态解释
执行flyway -X info
命令可以查看当前库的脚本执行状态:
+-----------+---------+----------------------------+------+---------------------+--------+
| Category | Version | Description | Type | Installed On | State |
+-----------+---------+----------------------------+------+---------------------+--------+
| Versioned | 1.0.1 | Init Schema 0.3 | SQL | 2018-06-11 19:05:41 | Future |
| Versioned | 1.0.2 | Alter system authority 0.3 | SQL | 2018-06-11 19:05:41 | Future |
+-----------+---------+----------------------------+------+---------------------+--------+
Future
: 脚本曾经执行成功,但在当前环境不存在(info命令更新状态)。Missing
: 脚本在当前环境不存在(migrate 命令更新状态)。Success
: 执行成功(migrate 命令更新状态)。Failed
: 执行失败(migrate命令更新状态)。Pending
: 还未执行(info命令更新状态)。
命令行使用
执行安装目录下的flyw.cmd
即可。
注意事项
-
命令区分大小写: ` flyway -X Validate
执行失败
flyway -X validate` 执行成功 -
版本记录的是整个sql文件的内容,如果修改了已经执行过的版本的SQL文件中的任意内容(即使是加了个空格),也会导致校验不通过。
ERROR: Unexpected error
org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 0.3
-> Applied to database : -1854357789
-> Resolved locally : 1683372801
at org.flywaydb.core.Flyway.doValidate(Flyway.java:1037)
at org.flywaydb.core.Flyway.access$100(Flyway.java:78)
at org.flywaydb.core.Flyway$2.execute(Flyway.java:1007)
at org.flywaydb.core.Flyway$2.execute(Flyway.java:1000)
at org.flywaydb.core.Flyway.execute(Flyway.java:1238)
at org.flywaydb.core.Flyway.validate(Flyway.java:1000)
at org.flywaydb.commandline.Main.executeOperation(Main.java:165)
at org.flywaydb.commandline.Main.main(Main.java:108)
-
baseline是基于当前数据库内容做为一个基础版本,并设置版本号为1.0。如果后续版本号小于1.0的SQL文件,将不会执行。
-
在一个空数据库中,如果当前的SQL文件版本号小于1,那么执行migrate,将不会执行版本号小于1的SQL脚本。因此初始版本号不能小于1。
集成到Spring Boot
pom.xml 引入依赖
可以不用指定版本号,在spring-boot-dependencies
指定了当前Spring Boot对应的版本号,例如Spring Boot 2.0对应版本为5.0.7。
<!-- flyway -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
SQL文件存放位置
src/main/resources/db/migration
Spring Boot配置
参考:Execute Flyway Database Migrations on Startup
Spring Boot集成了Flyway,如果没有特殊要求,只需要引入 flyway-core
包即可。
详细配置见:Common application properties
默认在启动之后会执行flyway migrate
命令,SQL文件使用默认的位置classpath:db/migration
,数据源使用的当前项目配置的数据源。因此如果使用的第三方数据源,可能会存在一些兼容性问题。例如druid就不能在数据库未初始化flyway库的情况下,启用wall(SQL注入防火墙),否则会报错并执行失败。因此可以在命令行手动执行flyway -X migrate
初始化数据库。
Java 手动执行命令
flyway也可以手动执行,执行代码如下:
import org.flywaydb.core.Flyway;
...
Flyway flyway = new Flyway();
flyway.setDataSource(url, user, password);
flyway.migrate();
坑点
-
. 不支持回滚到某个版本,如果需要回退,必须先clean所有,再执行migrate恢复到指定版本。(注意clean之前先备份)
flyway migrate
flyway migrate -target=1.0.1.002
-
. 尽量不要在SQL文件中使用DROP 等指令去手动控制版本,让版本依赖于SQL文件执行的顺序。
-
. Spring Boot如果使用的数据源是Druid,那么Flyway未初始化的数据库,执行migrate操作会报错,原因是druid的wall(SQL注入防火墙)会将flayway创建
flyway_schema_history
表的建表语句中的注释当成SQL注入风险,被拦截掉,从而导致创建flyway_schema_history
表失败。报错内容如下:
Script failed
-------------
SQL State : null
Error Code : 0
Message : sql injection violation, comment not allow : CREATE TABLE `expert_platform_backup`.`flyway_schema_history` (
`installed_rank` INT NOT NULL,
`version` VARCHAR(50),
`description` VARCHAR(200) NOT NULL,
`type` VARCHAR(20) NOT NULL,
`script` VARCHAR(1000) NOT NULL,
`checksum` INT,
`installed_by` VARCHAR(100) NOT NULL,
`installed_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`execution_time` INT NOT NULL,
`success` BOOL NOT NULL,
-- Add the primary key as part of the CREATE TABLE statement in case `innodb_force_primary_key` is enabled
CONSTRAINT `flyway_schema_history_pk`PRIMARY KEY (`installed_rank`)
) ENGINE=InnoDB
Line : 17
Statement : CREATE TABLE `xxxx`.`flyway_schema_history` (
`installed_rank` INT NOT NULL,
`version` VARCHAR(50),
`description` VARCHAR(200) NOT NULL,
`type` VARCHAR(20) NOT NULL,
`script` VARCHAR(1000) NOT NULL,
`checksum` INT,
`installed_by` VARCHAR(100) NOT NULL,
`installed_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`execution_time` INT NOT NULL,
`success` BOOL NOT NULL,
-- Add the primary key as part of the CREATE TABLE statement in case `innodb_force_primary_key` is enabled
CONSTRAINT `flyway_schema_history_pk`PRIMARY KEY (`installed_rank`)
) ENGINE=InnoDB
- 如果SQL中包含了类似于以下的SQL注释,在druid数据源执行中也会报错,但不影响最终结果。
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
在Mysql数据执行失败不会自动回滚,需要手动回滚。
-
Mysql SQL语句中不能有锁表和解锁表操作,会导致对
flyway_schema_history
表解锁表操作失败。