文章目录
  1. 1. 简介
  2. 2. 准备环境
  3. 3. 版本管理
  4. 4. 历史数据库
  5. 5. 其它

Flyway是一个用Java编写的开源数据库版本管理工具,或者说是数据库结构变更工具,旨在帮助开发和运维更容易地管理数据库演进过程中的各个版本。它的源代码在github上。

简介

在开发过程中,数据库是不断向前演进的,可以说是拥有“版本”这个概念。通常当在生产环境部署新代码的时候,会由开发或者DBA来做数据库结构变更的操作。当数据库较小,环境数量少的时候,人工操作比较有把握,直接就人肉来做结构变更了。可要是在数据库复杂、环境数量多(开发、测试、预发布、生产……)的情况下,人工处理这样的事就开始有些令人担心了。如何保证所有环境的数据库结构是一致的?如何知道当前环境的数据库是哪个状态?如何知道生产环境的一个关于数据库的hotfix是否也在预发布环境中执行了?Flyway就是用来解决这样的问题的工具。它的原理非常简单,就是在数据库中创建一张自己用的表,例如schema_version,在里面存放数据库当前的状态,以此来管理数据库的版本。Flyway提供了命令行APIMavenGradleAntSBT等各种方式,来让我们更容易将其与自己的项目结合。类似的工具还有Liquibasedbdeploy等。

本文将会用Docker来创建一个mysql的实例,用Maven来创建一个包含数据库的Java项目,并使用Flyway来进行版本管理。

准备环境

首先请自行安装Docker、Java、Maven和喜欢的IDE。我用的是Intellij IDEA社区版。我用Vagrant启动了一台已经安装过Docker的Ubuntu虚拟机,它的IP是192.168.33.88,可以用以下命令来直接启动mysql容器来提供数据库服务并创建ggg数据库:

1
2
docker run -d --net=host --name=mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.12
docker exec -it mysql mysql -uroot -p123456 -e 'create database ggg;'

接下来新建一个Maven工程helloFlyway:

1
2
3
4
5
6
7
8
mvn archetype:generate -B \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.1 \
-DgroupId=org.ggg.flyway \
-DartifactId=helloFlyway \
-Dversion=1.0-SNAPSHOT \
-Dpackage=org.ggg.flyway

helloFlyway/pom.xml里加入flyway的maven插件和mysql-connector-java的依赖(别忘了根据你自己的数据库来配置jdbc):

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<project ...>
...
<build>
<plugins>
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>4.0.3</version>
<configuration>
<url>jdbc:mysql://192.168.33.88:3306/ggg</url>
<user>root</user>
<password>123456</password>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

接下来创建一个数据库版本1的文件:

1
2
3
4
5
6
7
8
cd helloFlyway
mkdir -p src/main/resources/db/migration/
cat << EOF > src/main/resources/db/migration/V1__Create_person_table.sql
create table PERSON (
ID int not null,
NAME varchar(100) not null
);
EOF

工程创建好并用intellij导入后,应该是这样的:

版本管理

使用以下命令来运行flyway:

1
mvn flyway:migrate

出现BUILD SUCCESS就说明数据库结构变更已经完成了。我们可以登录到数据库看一看:

1
docker exec -it mysql mysql -uroot -p123456

运行以下sql就可以看到flyway确实已经起作用了:

1
2
3
USE ggg
SHOW TABLES;
SELECT * FROM schema_version;

而表schema_version里面也有了一条记录。接下来再创建一个数据库版本2的文件:

1
2
3
4
5
cat << EOF > src/main/resources/db/migration/V2__Add_people.sql
insert into PERSON (ID, NAME) values (1, 'Axel');
insert into PERSON (ID, NAME) values (2, 'Mr. Foo');
insert into PERSON (ID, NAME) values (3, 'Ms. Bar');
EOF

再次用同一条命令来运行flyway:

1
mvn flyway:migrate

就会看到日志里显示Current version of schema `ggg`: 1Migrating schema `ggg` to version 2 - Add people。如果我们重复运行mvn flyway:migrate,就会看到Schema `ggg` is up to date. No migration necessary。现在查看一下两张表:

1
2
SELECT * FROM PERSON;
SELECT * FROM schema_version;

PERSON表里已经有了V2__Add_people.sql里的三条记录,而schema_version表里,就可以看到现在的版本为2。通过这样的方式,就可以管理数据库的版本了。

历史数据库

如果数据库里已经有历史数据了,那就会稍微麻烦一点儿。我们来试试看,首先改造一下ggg数据库:

1
2
RENAME TABLE PERSON TO STUDENT;
DROP TABLE schema_version;

这样一来,数据库的版本便被清空,PERSON表也变成了STUDENT表。如果直接运行mvn flyway:migrate会报错:org.flywaydb.core.api.FlywayException: Found non-empty schema `ggg` without metadata table。这时候需要用到另一个命令:

1
mvn flyway:baseline

上面的baseline命令会以现在的数据库结构为基础,创建一张schema_version表,标明现在的版本是1。接着运行mvn flyway:migrate还会报错:Migration of schema ggg to version 2 - Add people failed。这是因为数据库现在是版本1,所以会忽略V1__Create_person_table.sql而直接执行V2__Add_people.sql,而V2__Add_people.sql依赖于V1__Create_person_table.sql里创建的PERSON表,所以失败了。解决的方法也很简单,改变两个sql文件的版本即可:

1
2
3
mv src/main/resources/db/migration/V1__Create_person_table.sql src/main/resources/db/migration/V1_1__Create_person_table.sql
mv src/main/resources/db/migration/V2__Add_people.sql src/main/resources/db/migration/V1_2__Add_people.sql
mvn flyway:migrate

Flyway的命名规范如下:以V开头,.sql结尾,版本号可以使用.或者_,版本号和描述之间用两个下划线__分开。要是执行成功,但是却看不到PERSON表,那很可能是因为schema_version表里的版本已经是一个错误的版本2了,运行repair之后再重新migrate即可:

1
2
mvn flyway:repair
mvn flyway:migrate

其它

Flyway认为没有必要支持回滚。可以通过mvn flyway:info命令来查看数据库的版本和和需要执行的sql脚本。通过mvn flyway:clean来清空数据库,这条命令对于测试很方便,但是千万要小心生产环境!!!此外,还有一个较常用的命令:mvn flyway:validate可以验证是否所有的sql都已经在数据库上运行完毕了。

文章目录
  1. 1. 简介
  2. 2. 准备环境
  3. 3. 版本管理
  4. 4. 历史数据库
  5. 5. 其它