

Spring Boot 2.x基础教程:使用Flyway管理数据库版本
source link: http://blog.didispace.com/spring-boot-learning-24-3-11/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

之前已经介绍了很多在Spring Boot中使用MySQL的案例,包含了Spring Boot最原始的JdbcTemplate、Spring Data JPA以及我们国内最常用的MyBatis。同时,对于一些复杂场景比如:更换Druid数据源,或是多数据源的情况也都做了介绍。
不论我们使用哪一个具体实现框架,都离不开对数据库表结构的管理。而这一类管理一直都存在一个问题:由于数据库表元数据存储于数据库中,而我们的访问逻辑都存在于Git或其他代码仓库中。Git已经帮助我们完成了代码的多版本管理,那么数据库中的表该如何做好版本控制呢?
今天我们就来介绍在Spring Boot中使用Flyway来管理数据库版本的方法。
Flyway简介
Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等,还提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。
官方网站: https://flywaydb.org/
本文对于Flyway的自身功能不做过多的介绍,读者可以通过阅读官方文档或利用搜索引擎获得更多资料。下面我们具体说说在Spring Boot应用中的应用,如何使用Flyway来创建数据库以及结构不一致的检查。
动手试试
下面我们先预设一个开发目标:
- 假设我们需要开发一个用户管理系统,那么我们势必要设计一张用户表,并实现对用户表的增删改查操作。
- 在任务1的功能完成之后,我们又有一个新需求,需要对用户表增加了一个字段,看看如何实现对数据库表结构的更改。
目标 1 的实现
第一步:创建一个基础的Spring Boot项目,并在 pom.xml
中加入Flyway、MySQL连接和数据访问相关的必要依赖(这里选用 spring-boot-starter-jdbc
作为例子)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
第二步:按Flyway的规范创建版本化的SQL脚本。
- 在工程的
src/main/resources
目录下创建db
目录,在db
目录下再创建migration
目录 - 在
migration
目录下创建版本化的SQL脚本V1__Base_version.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(5) DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意:如果你不想将SQL脚本放到其他目录,可以用 spring.flyway.locations
参数来配置。这里不同于1.x版本的配置项 flyway.locations
第三步:根据User表的结构,编写对应的实体定义
@Data @NoArgsConstructor public class User { private Long id; private String name; private Integer age; }
第四步:编写用户操作接口和实现
public interface UserService { /** * 新增一个用户 * * @param name * @param age */ int create(String name, Integer age); /** * 根据name查询用户 * * @param name * @return */ List<User> getByName(String name); /** * 根据name删除用户 * * @param name */ int deleteByName(String name); /** * 获取用户总量 */ int getAllUsers(); /** * 删除所有用户 */ int deleteAllUsers(); } @Service public class UserServiceImpl implements UserService { private JdbcTemplate jdbcTemplate; UserServiceImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public int create(String name, Integer age) { return jdbcTemplate.update("insert into USER(NAME, AGE) values(?, ?)", name, age); } @Override public List<User> getByName(String name) { List<User> users = jdbcTemplate.query("select * from USER where NAME = ?", (resultSet, i) -> { User user = new User(); user.setId(resultSet.getLong("ID")); user.setName(resultSet.getString("NAME")); user.setAge(resultSet.getInt("AGE")); return user; }, name); return users; } @Override public int deleteByName(String name) { return jdbcTemplate.update("delete from USER where NAME = ?", name); } @Override public int getAllUsers() { return jdbcTemplate.queryForObject("select count(1) from USER", Integer.class); } @Override public int deleteAllUsers() { return jdbcTemplate.update("delete from USER"); } }
这里主要介绍Flyway的应用,所以采用这种比较简单的编写方式,实际项目应用中,还是推荐MyBatis的具体操作实现。
第五步:编写测试用例
@Slf4j @SpringBootTest public class Chapter311ApplicationTests { @Autowired private UserService userSerivce; @Test public void test() throws Exception { userSerivce.deleteAllUsers(); // 插入5个用户 userSerivce.create("Tom", 10); userSerivce.create("Mike", 11); userSerivce.create("Didispace", 30); userSerivce.create("Oscar", 21); userSerivce.create("Linda", 17); // 查询名为Oscar的用户,判断年龄是否匹配 List<User> userList = userSerivce.getByName("Oscar"); Assertions.assertEquals(21, userList.get(0).getAge().intValue()); // 查数据库,应该有5个用户 Assertions.assertEquals(5, userSerivce.getAllUsers()); // 删除两个用户 userSerivce.deleteByName("Tom"); userSerivce.deleteByName("Mike"); // 查数据库,应该有5个用户 Assertions.assertEquals(3, userSerivce.getAllUsers()); } }
注意由于Spring Boot 2.4应用的junit版本与之前Spring Boot 1.x版本中的不同,因此单元测试的编写略有区别,有兴趣的读者可以分别查看之前介绍文章和这篇文章中的单元测试的区别,这里就不细说了。
第六步:运行上面编写的单元测试,验证一下效果。
不出意外,单元测试运行ok的话
连上数据库看看。此时应该多出了这两张表:
user flyway_schema_history
目标 2 的实现
有了上面的基础之后,我们来说说后续要做表结构的表变动该怎么操作,这也是之前读者出现问题最多的情况,所以在2.x版本教程中特地讲一讲。
首先,大家在开始使用Flyway之后,对于数据库表接口的变更就要关闭这几个途径:
- 直接通过工具登录数据去修改表结构
- 已经发布的sql脚本不允许修改
正确的表结构调整途径:在flyway脚本配置路径下编写新的脚本,启动程序来执行变更。这样可以获得几个很大的好处:
- 脚本受Git版本管理控制,可以方便的找到过去的历史
- 脚本在程序启动的时候先加载,再提供接口服务,一起完成部署步骤
- 所有表结构的历史变迁,在管理目录中根据版本号就能很好的追溯
下面根据一个实际需求来具体操作下。假设我们现在想对User表增加一个字段:address,用来存储用户的通讯地址,那么我们就需要这样操作实现。
第一步:创建脚本文件 V1_1__alter_table_user.sql
,并写入增加 address
列的语句
ALTER TABLE `user` ADD COLUMN `address` VARCHAR(20) DEFAULT NULL;
对于脚本文件名的基本规则是: 版本号__描述.sql
。当然如果你有更细致的要求,那么可以做更细致的文件名规划,具体细节读者可以查阅文末参考资料中的官方文档获取。
第二步:再次执行单元测试,在控制台中可以看到如下日志:
2021-01-11 16:58:12.025 INFO 37330 --- [ main] o.f.c.i.database.base.DatabaseType : Database: jdbc:mysql://localhost:3306/test (MySQL 8.0) 2021-01-11 16:58:12.063 INFO 37330 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.020s) 2021-01-11 16:58:12.075 INFO 37330 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test`: 1 2021-01-11 16:58:12.082 INFO 37330 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `test` to version "1.1 - alter table user" 2021-01-11 16:58:12.113 INFO 37330 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `test` (execution time 00:00.045s)
再查看一下数据中国的内容:
如果你还没有体会到引入Flyway对给我们的表结构带来的好处的话,不妨也留言分享下你们的管理方式吧!
更多本系列免费教程连载「点击进入汇总目录」
代码示例
本文的相关例子可以查看下面仓库中的 chapter3-11
目录:
- Github: https://github.com/dyc87112/SpringBoot-Learning/
- Gitee: https://gitee.com/didispace/SpringBoot-Learning/
如果您觉得本文不错,欢迎 Star
支持,您的关注是我坚持的动力!
Recommend
-
23
本文大纲 flyway是什么 能帮助我们解决什么问题 springboot环境下使用flyway flyway的工...
-
40
在项目迭代开发中,难免会有更新数据库 Schema 的情况,比如添加新表、在表中增加字段或者删除字段等,那么当我对数据库进行一系列操作后,如何快速地在其他同事的电脑上同步?如何在测试/生产服务器上快速同步?
-
7
Flyway 助力数据库脚本自动化管理攻略 发表于 2019-10-21 | 数据存储 | MySQL ...
-
10
Spring Boot 2.x基础教程:使用LDAP来管理用户与组织数据 ...
-
4
除了最常用的关系数据库和缓存之外,之前我们已经介绍了在Spring Boot中如何配置和使用MongoDB、LDAP这些存储的...
-
7
在如今的关系型数据库中,有两个开源产品是你必须知道的。其中一个是MySQL,相信关注我的小伙伴们一定都不陌生,因为之前的Spring Boot关于关系型数据库的所有例子都是对MySQL来介绍的。而今天我们将介绍另外一个开源关系型数据库:PostgreSQL...
-
9
SpringBoot数据库管理 - 用flyway对数据库管理和迁移 作...
-
5
SpringBoot数据库管理 - 用flyway对数据库管理和迁移 推荐 原创 上文介绍了Liquibase,以及和SpringBoot的集成。除了Liq...
-
4
Overview This tutorial helps you configure Flyway as the database migration tool in your Spring Boot project. Spring boot has extensive support for Flyway migration so you should not have any problem adding/configuring this dependency.
-
12
SivaLabsJava, Spring Boot, Microservices, Cloud and DevOps TutorialsShare this post:
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK