Spring Boot 集成 Flyway 实现数据库版本控制
在项目迭代开发中,难免会有更新数据库 Schema 的情况,比如添加新表、在表中增加字段或者删除字段等,那么当我对数据库进行一系列操作后,如何快速地在其他同事的电脑上同步?如何在测试/生产服务器上快速同步?

每次发版的时候,由于大家都可能有 sql 更改情况,这样就会有以下痛点:
- 忘记某些 sql 修改
- 每个开发人员的 sql 的执行顺序问题
- 重复更新
- 需要手动去数据库执行脚本
以上问题以及痛点可以通过 Flyway 工具来解决,Flyway 可以实现自动化的数据库版本管理,并且能够记录数据库版本更新记录。
Flyway 简介
Flyway 是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具。用通俗的话讲,Flyway 可以像 Git 管理不同人的代码那样,管理不同人的 sql 脚本,从而做到数据库同步,更多的信息可以在 Flyway 的官网上进行阅读学习。
另外 Flyway 支持很多关系数据库,具体如下所示:

下面我们在 Spring Boot 中集成 Flyway 来实现数据库版本控制。
Spring Boot 集成 Flyway
首先创建一个 SpringBoot 项目,然后在 pom.xml 加入如下依赖集成 Flyway:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.4</version>
</dependency>
然后在 application.yml 中写入 mysql 的配置及 Flyway 的相关配置(Flyway locations 默认读取当前项目下的 resources/db/migration 目录)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
spring.flyway.locations=classpath:/db/migration/
接下来,在 resources/db/migration 目录下创建需要执行的 SQL 脚本即可。
其中,SQL 脚本命名规范如下:

- Prefix 前缀:V 代表版本迁移,U 代表撤销迁移,R 代表可重复迁移
- Version 版本号:版本号通常
.和整数组成 - Separator 分隔符:固定由两个下划线
__组成 - Description 描述:由下划线分隔的单词组成,用于描述本次迁移的目的
- Suffix 后缀:如果是 SQL 文件那么固定由
.sql组成,如果是基于 Java 类则默认不需要后缀
那么,我们按照命名规范在 resources/db/migration 目录下,创建 V1.0__init_db.sql SQL 迁移脚本,具体内容如下:
DROP TABLE IF EXISTS `user` ;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(20) NOT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` (`id`, `name`, `age`) VALUES ('1', 'wupx', '18');
最后启动项目,执行日志如下所示:
2020-05-07 12:41:29.126 INFO 13732 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2020-05-07 12:41:29.236 INFO 13732 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:mysql://localhost:3306/test (MySQL 5.5)
2020-05-07 12:41:29.287 INFO 13732 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.009s)
2020-05-07 12:41:29.330 INFO 13732 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table: `test`.`flyway_schema_history`
2020-05-07 12:41:29.479 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test`: << Empty Schema >>
2020-05-07 12:41:29.480 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `test` to version 1.0 - init db
2020-05-07 12:41:29.481 WARN 13732 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Unknown table 'user' (SQL State: 42S02 - Error Code: 1051)
2020-05-07 12:41:29.631 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `test` (execution time 00:00.301s)
从启动日志中可以看出,Flyway 监测到需要运行版本脚本来初始化数据库,因此执行了 V1.0__init_db.sql 脚本,从而创建了 user 表,另外还自动创建了 flyway_schema_history 表,用于记录所有版本演化和状态,其表结构如下(以 MySQL 为例):
| Field | Type | Null | Key | Default |
|---|---|---|---|---|
| version_rank | int(11) | NO | MUL | NULL |
| installed_rank | int(11) | NO | MUL | NULL |
| version | varchar(50) | NO | PRI | NULL |
| description | varchar(200) | NO | NULL | |
| type | varchar(20) | NO | NULL | |
| script | varchar(1000) | NO | NULL | |
| checksum | int(11) | YES | NULL | |
| installed_by | varchar(100) | NO | NULL | |
| installed_on | timestamp | NO | CURRENT_TIMESTAMP | |
| execution_time | int(11) | NO | NULL | |
| success | tinyint(1) | NO | MUL | NULL |
查询 flyway_schema_history 表,发现增加了一条版本号为 1.0 的,使用 V1.0__init_db.sql 迁移脚本的记录。
mysql> SELECT * FROM flyway_schema_history;
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
| installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success |
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
| 1 | 1.0 | init db | SQL | V1.0__init_db.sql | 1317299633 | root | 2020-05-07 12:41:29 | 97 | 1 |
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
再去查询 user 表,发现 sql 脚本中的数据也插入成功了。
mysql> SELECT * FROM user;
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | wupx | 18 |
+----+------+-----+
接下来再次运行项目,结果如下:
2020-05-07 15:34:49.843 INFO 41880 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2020-05-07 15:34:49.981 INFO 41880 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:mysql://localhost:3306/test (MySQL 5.5)
2020-05-07 15:34:50.036 INFO 41880 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.013s)
2020-05-07 15:34:50.043 INFO 41880 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test`: 1.0
2020-05-07 15:34:50.043 INFO 41880 --- [ main] o.f.core.internal.command.DbMigrate : Schema `test` is up to date. No migration necessary.
从日志中可以看出,Flyway 发现一个迁移脚本,也就是 V1.0__init_db.sql,经过判断已经到达最新版本 1.0,无需执行迁移。
接下来,我们在 V1.0__init_db.sql 迁移脚本中添加一条 INSERT 操作:INSERT INTO user (id, name, age) VALUES ('2', 'huxy', '18'); ,再次启动项目,会报如下错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 1.0
-> Applied to database : 1317299633
-> Resolved locally : -1582367361
这个错误的原因就是 Flyway 会给脚本计算一个 checksum 保存在数据库中,用于在之后运行过程中对比 sql 文件是否有变化,如果发生了变化,则会报错,也就防止了误修改脚本导致发生问题。
总结
Flyway 可以有效改善数据库版本管理方式,并且是一款 Java 开源的数据库迁移管理工具,具有轻便小巧的特点,可以无门槛快速集成到项目中,如果项目中还未使用,不防尝试一下,想了解更多的可以去官网查看文档学习。
本文的完整代码在 https://github.com/wupeixuan/SpringBoot-Learn 的 database-version-control 目录下。
最好的关系就是互相成就,大家的在看、转发、留言三连就是我创作的最大动力。
参考
Spring Boot 集成 Flyway 实现数据库版本控制的更多相关文章
- Flyway 的使用及Spring Boot集成Flyway
一.简单介绍 Flyway 是一个开源.跨环境的数据库迁移工具,它强烈主张简单性和约定性而不是配置. Flyway 是一个便于多人开发对数据库管理的工具,将sql语句写入文件中,只需要在控制台输入指令 ...
- Spring boot入门(二):Spring boot集成MySql,Mybatis和PageHelper插件
上一篇文章,写了如何搭建一个简单的Spring boot项目,本篇是接着上一篇文章写得:Spring boot入门:快速搭建Spring boot项目(一),主要是spring boot集成mybat ...
- Spring Boot集成JPA的Column注解命名字段无效的问题
偶然发现,Spring Boot集成jpa编写实体类的时候,默认使用的命名策略是下划线分隔的字段命名. Spring Boot版本:1.5.4.release 数据表: id int, userNam ...
- Quartz与Spring Boot集成使用
上次自己搭建Quartz已经是几年前的事了,这次项目中需要定时任务,需要支持集群部署,想到比较轻量级的定时任务框架就是Quartz,于是来一波. 版本说明 通过搜索引擎很容易找到其官网,来到Docum ...
- Spring Boot 2 (八):Spring Boot 集成 Memcached
Spring Boot 2 (八):Spring Boot 集成 Memcached 一.Memcached 介绍 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数 ...
- Spring Boot 集成Shiro和CAS
Spring Boot 集成Shiro和CAS 标签: springshirocas 2016-01-17 23:03 35765人阅读 评论(22) 收藏 举报 分类: Spring(42) 版 ...
- Spring Boot集成MyBatis开发Web项目
1.Maven构建Spring Boot 创建Maven Web工程,引入spring-boot-starter-parent依赖 <project xmlns="http://mav ...
- 详解Spring Boot集成MyBatis的开发流程
MyBatis是支持定制化SQL.存储过程以及高级映射的优秀的持久层框架,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集. spring Boot是能支持快速创建Spring应用的Java框 ...
- Spring Boot 集成 FreeMarker 详解案例(十五)
一.Springboot 那些事 SpringBoot 很方便的集成 FreeMarker ,DAO 数据库操作层依旧用的是 Mybatis,本文将会一步一步到来如何集成 FreeMarker 以及配 ...
随机推荐
- 本地项目推送到Github
1.在github上repositories新建一个git项目工程 2.使用git,把刚建好的项目clone到本地 3.把本地项目中的文件全部移动到下载下来的git项目中,以下是我本地项目中的文件 4 ...
- loadrunner post请求
注意:loadrunner参数中的引号,需要自己加"\" post 请求,分为header 和body两个部分处理 header部分比较容易处理,使用函数实现,如web_add_h ...
- MVC学习的心路历程
2020/4/17 之前接触过三层架构,但是没有接触过mvc,所以有点蒙,所以现在在一步步构建思路. 1.了解MVC的发展,做一个简单的项目.
- L13过拟合欠拟合及其解决方案
过拟合.欠拟合及其解决方案 过拟合.欠拟合的概念 权重衰减 丢弃法 模型选择.过拟合和欠拟合 训练误差和泛化误差 在解释上述现象之前,我们需要区分训练误差(training error)和泛化误差(g ...
- .NET Core 发布时去掉多余的语言包文件夹
用 .NET Core 3.x 作为目标框架时发布完之后,会发现多了很多语言包文件夹,类似于: 有时候,不想要生成这些语言包文件夹,需要稍微配置一下. 在 PropertyGroup 节点中添加如下的 ...
- 阿里面试官让我实现一个线程安全并且可以设置过期时间的LRU缓存,我蒙了!
目录 1. LRU 缓存介绍 2. ConcurrentLinkedQueue简单介绍 3. ReadWriteLock简单介绍 4.ScheduledExecutorService 简单介绍 5. ...
- git多人协作操作流程
git协作工作流程 git checkout work 自己工作分支工作 git commit -a -m ''自己工作分支提交 git checkout master 切换到主分支 git pull ...
- 详解 I/O流
I/O流是用于处理设备之前信息传输的流,在我们今后的学习甚至是工作中,都是十分重要的. 在我们的日常生活中,也是很常见的,譬如:文件内容的合并.设备之键的文件传输,甚至是下载软件时的断点续传,都可以用 ...
- this 关键字的用法
用法一 this代表当前类的实例对象 class Program { static void Main(string[] args) { tr ...
- Java IO 流-- 字节数组流ByteArrayInPutStream ByteArrayOutPutStream
字节数组流输于缓冲流,放在jvm内存中,java可以直接操作.我们使用时可以不用关闭,交给GC垃圾回收机制处理. 当然我们为了保持良好习惯和代码一致性也可以加上关闭语句. 当其实我么打开ByteArr ...