之前曾经介绍了很多在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. 假如咱们须要开发一个用户管理系统,那么咱们势必要设计一张用户表,并实现对用户表的增删改查操作。
  2. 在工作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@NoArgsConstructorpublic 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();}@Servicepublic 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@SpringBootTestpublic 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表就是咱们保护在SQL脚本中要创立的表
  • flyway_schema_history表是flyway的治理表,用来记录在这个数据库上跑过的脚本,以及每个脚本的查看根据。这样每次利用启动的时候,就能够晓得哪个脚本须要运行,或者哪个脚本产生了变动,运行根底可能不对,造成数据结构的凌乱而阻止运行。

指标 2 的实现

有了下面的根底之后,咱们来说说后续要做表构造的表变动该怎么操作,这也是之前读者呈现问题最多的状况,所以在2.x版本教程中顺便讲一讲。

首先,大家在开始应用Flyway之后,对于数据库表接口的变更就要敞开这几个路径:

  1. 间接通过工具登录数据去批改表构造
  2. 曾经公布的sql脚本不容许批改

正确的表结构调整路径:在flyway脚本配置门路下编写新的脚本,启动程序来执行变更。这样能够取得几个很大的益处:

  1. 脚本受Git版本管理控制,能够不便的找到过来的历史
  2. 脚本在程序启动的时候先加载,再提供接口服务,一起实现部署步骤
  3. 所有表构造的历史变迁,在治理目录中依据版本号就能很好的追溯

上面依据一个理论需要来具体操作下。假如咱们当初想对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`: 12021-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反对,您的关注是我保持的能源!

参考资料

  • Spring Boot中应用Flyway来治理数据库版本
  • Flyway官网文档
欢送关注我的公众号:程序猿DD,取得独家整顿的收费学习资源助力你的Java学习之路!另每周赠书不停哦~