一、前言
一般在我们开发项目的时候经常会更新数据库表的字段,如果同事 a 添加了表字段,没有及时给同事 b sql 脚本,可能同事 b 的代码运行就会报错,而且随着时间的推移,sql 脚本越来越多,项目上线的时候整理起来就很费时间,所以就有大佬级别的人物创造了 flyway 这个数据库版本管理工具。
flyway 是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。flyway 可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,migrations 可以写成 sql 脚本,也可以写在 java 代码中,不仅支持 command line 和 java api,还支持 build 构建工具和 spring boot 等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。
二、flyway介绍
2.1 主要特性
1.普通 sql:纯 sql 脚本(包括占位符替换)没有专有的xml格式,没有锁定
2.无限制:使用 java 代码来进行一些高级数据操作
3.零依赖:只需运行在 java6(及以上)和数据库所需的 jdbc 驱动
4.约定优于配置:迁移时,自动查找系统文件和类路径中的 sql 文件或 java 类
5.高可靠性:在集群环境下进行数据库升级是安全可靠的
6.云支持:完全支持 microsoft sql azure, google cloud sql & app engine、heroku postgres 和 amazon rds
7.自动迁移:使用 flyway 提供的 api,让应用启动和迁移同时工作
8.快速失败:损坏的数据库或失败的迁移可以防止应用程序启动
9.数据库清理:在一个数据库中删除所有的表、视图、触发器,而不是删除数据库本身
2.2 运行原理
当 flyway 连接数据库中的 schema 后,会先检查是否已存在 flyway_schema_history 表,如果没有则创建。该表用于跟踪数据库的状态,如数据迁移的版本,迁移成功状态等信息。
当 flyway_schema_history 存在后,flyway 会扫描文件系统或应用中的 classpath 目录的数据迁移文件,然后根据它们的版本号进行按序迁移,如下图:

由于 flyway_schema_history 表中记录了迁移的版本号,如果文件的版本号小于或等于标记为当前版本的版本号,则忽略它们不执行。
在实际使用中,flyway有两种方式执行,一种是构建项目的时候执行,一种是项目启动的时候执行。
上边描述的内容或许对读者来说还不够直观,那么下面我们就开始进行实战演练。
三、构建实战
环境:
mysql-5.7.30
springboot 2.3.5.release
新建一个 maven 项目。
3.1 添加依赖
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.flywaydb</groupid>
<artifactid>flyway-core</artifactid>
</dependency>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<scope>runtime</scope>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-jdbc</artifactid>
</dependency>注意:
如果构件项目的时候执行flyway,那么就必须引入spring-boot-starter-jdbc依赖。
3.2 配置数据迁移文件
在项目的 src/main/resources 下创建 db/migration 目录,该目录下放置需要数据迁移的文件。
数据迁移文件默认名称格式为:v[version]__[name].sql。
注意:
名称中[version]和[name]之间是两个下划线!
本次测试新建名为 v0.1.0__init_table.sql 的文件,内容如下:
use flywaydb;
drop table if exists user;
create table user
(
id bigint(20) not null comment '主键id',
name varchar(30) null default null comment '姓名',
age int(11) null default null comment '年龄',
email varchar(50) null default null comment '邮箱',
primary key (id)
);我们再新建一个名为 v0.1.1__init_data.sql 文件,内容如下:
insert into user (id, name, age, email) values (1, 'jone', 18, 'test1@baomidou.com'), (2, 'jack', 20, 'test2@baomidou.com'), (3, 'tom', 28, 'test3@baomidou.com'), (4, 'sandy', 21, 'test4@baomidou.com'), (5, 'billie', 24, 'test5@baomidou.com');
版本 1 数据迁移的内容是创建一张 user 表。
3.3 配置application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.driver
url: jdbc:mysql://localhost:3306/flywaydb?createdatabaseifnotexist=true&servertimezone=utc&useunicode=true&characterencoding=utf-8&usessl=true
username: root
password: 123456
flyway:
enabled: true # 禁止清理数据库表
table: flywayinit #修改原数据表名,默认为schema_version编译项目结果如下图:


图中,数据库 flywaydb 中创建了 flywayinit 表和 user 表,数据成功迁移到指定数据库中。
当系统升级时又需要做数据迁移,我们只需在 db/migration 目录下再放置新版本的 sql 文件即可。
版本 0.1.1 的数据迁移内容是往 user 表中插入 3 条数据。
上面我们在application.yml配置了flyway初始化的数据库,其实也可以配置好多相关参数,具体如下:
| 配置项 | 含义 |
|---|---|
| flyway.baseline-description | 对执行迁移时基准版本的描述. |
| flyway.baseline-on-migrate | 当迁移时发现目标schema非空,而且带有没有元数据的表时,是否自动执行基准迁移,默认false. |
| flyway.baseline-version | 开始执行基准迁移时对现有的schema的版本打标签,默认值为1. |
| flyway.check-location | 检查迁移脚本的位置是否存在,默认false. |
| flyway.clean-on-validation-error | 当发现校验错误时是否自动调用clean,默认false. |
| flyway.enabled | 是否开启flywary,默认true. |
| flyway.encoding | 设置迁移时的编码,默认utf-8. |
| flyway.ignore-failed-future-migration | 当读取元数据表时是否忽略错误的迁移,默认false. |
| flyway.init-sqls | 当初始化好连接时要执行的sql. |
| flyway.locations | 迁移脚本的位置,默认db/migration. |
| flyway.out-of-order | 是否允许无序的迁移,默认false. |
| flyway.password | 目标数据库的密码. |
| flyway.placeholder-prefix | 设置每个placeholder的前缀,默认${. |
| flyway.placeholder-replacementplaceholders | 是否要被替换,默认true. |
| flyway.placeholder-suffix | 设置每个placeholder的后缀,默认}. |
| flyway.placeholders.[placeholder name] | 设置placeholder的value |
| flyway.schemas | 设定需要flywary迁移的schema,大小写敏感,默认为连接默认的schema. |
| flyway.sql-migration-prefix | 迁移文件的前缀,默认为v. |
| flyway.sql-migration-separator | 迁移脚本的文件名分隔符,默认__ |
| flyway.sql-migration-suffix | 迁移脚本的后缀,默认为.sql |
| flyway.table | flyway使用的元数据表名,默认为schema_version |
| flyway.target | 迁移时使用的目标版本,默认为latest version |
| flyway.url | 迁移时使用的jdbc url,如果没有指定的话,将使用配置的主数据源 |
| flyway.user | 迁移数据库的用户名 |
| flyway.validate-on-migrate | 迁移时是否校验,默认为true. |
四、启动方式实践
4.1 引入依赖
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.flywaydb</groupid>
<artifactid>flyway-core</artifactid>
</dependency>
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<scope>runtime</scope>
</dependency>4.2 修改application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.driver
url: jdbc:mysql://localhost:3306/flywaydb?createdatabaseifnotexist=true&servertimezone=utc&useunicode=true&characterencoding=utf-8&usessl=true
username: root
password: 1234564.3 编码
创建配置类flywayconfig.java
@configuration
public class flywayconfig {
@value("${spring.datasource.url}")
private string url;
@value("${spring.datasource.username}")
private string username;
@value("${spring.datasource.password}")
private string password;
@postconstruct
public void migrate() {
flyway flyway = flyway.configure().datasource(url, username, password).table("flyway_init_table").load();
// 创建 flyway_schema_history 表
//flyway.baseline();
// 删除 flyway_schema_history 表中失败的记录
//flyway.repair();
// 检查 sql 文件
//flyway.validate();
// 执行数据迁移
flyway.migrate();
// 删除当前 schema 下所有表
//flyway.clean();
}
}
在构建flyway的时候,构件方法和配置中的配置项类似。
4.4 启动测试
启动项目,结果如下图:


总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论