〇、数据库版本变更管理惨烈现状

开发环境、测试环境、生成环境同时存在多个数据库副本。
image-1669871722687

代码我们使用Git或者SVN能很好的管理版本,但是数据库呢?脚本呢?
不幸的是,我们做得并不好。许多项目仍然依赖于手动执行的SQL脚本。有时甚至没有(编写临时的SQL语句来解决问题)。

image-1669871739612
很快就会出现许多问题:
这台机器上的数据库处于什么状态?
某个SQL脚本是否已应用?
生产中的快速修复SQL是否在之后的测试环境中执行过?
如何创建一个新的数据库实例?
这些问题的答案往往是:我们不知道。

image-1669871805684
讲一个笑话:暴雪要重置60级经典版本魔兽世界,代码能找到、模型文件能找到、唯独当年版本的数据库找不到了。

一、技术选型Flyway和Liquibase

目前做数据库变更管理的Java开源库,做得好的就是Flyway和Liquibase。
下面我们比较一下这两个库的特性:
image-1669871941856

在我的实际使用中发现,Flyway 存在几个严重问题:

  • 最新社区版flyway仅支持5年内发布的的数据库版本,比如MySQL仅支持到8.0。
  • blob大字段不能导入。
  • 复杂数据(比如带转义符号和尖括号等数据)不能导入的问题。

在Liquibase中,以上三个问题均不存在。

二、Liquibase介绍

Liquibase 是用于数据库重构、管理、记录变化与回滚的开源工具。 在写代码的时候,我们使用 Git 或 subversion 对代码进行版本控制,在数据库中,我们可以使用 liquibase 对数据库表进行版本控制。

image-1669873813986

持续维护
2006年开源至今发布了73个版本、1.6k 的 fork 人数、3.4k 的 star 人数、11323 次 Commit
丰富的特性
SQL脚本、没有限制、零依赖、约定优于配置、集群高可靠、启动时自动迁移、失败时阻止服务启动
丰富的数据库支持
Apache Derby、CockroachDB、Firebird、H2、HSQL、Informix、InterBase、MariaDB、MSSQL、MySQL、Oracle、PostgreSQL、SQLite、Sybase Anywhere、Sybase Enterprise。
Java无缝集成
Java 8/9/10/11/12/13 兼容SpringBoot 自动配置 Maven、Gradle、Spring、Ant

三、工程集成

3.1 引入依赖jar

引入依赖包:

<!-- https://mvnrepository.com/artifact/org.liquibase/liquibase-core -->
<dependency>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-core</artifactId>
  <version>4.15.0</version>
</dependency>

如果你使用的数据库在默认支持范围,仅引用liquibase-core即可。如果是扩展支持的,需要根据数据库的不同引用扩展数据库jar包。
比如MongoDB:

<!-- https://mvnrepository.com/artifact/org.liquibase.ext/liquibase-mongodb -->
<dependency>
  <groupId>org.liquibase.ext</groupId>
  <artifactId>liquibase-mongodb</artifactId>
  <version>4.15.0</version>
</dependency>

3.2 配置注入

1.使用 db.changelog-master.yaml 配置文件

如果我们没有在 Spring Boot 中指定更改日志文件的位置,则YAML 的默认路径是 db/changelog/db.changelog-master.yaml.
image-1669874283849

2.使用 springboot 注解 @Configuration
image-1669874289202

3.3 配置SQL文件执行索引

1.在resources/db/changelog下创建DDL和DML文件夹,将我们的数据库脚本放入其中。
image-1669874344998

2.编辑db.changelog-master.yaml文件,将SQL文件地址写入,Liquibase会在工程启动时,按照顺序执行。
image-1669874387533

四、使用

4.1 SQL文件的编写

SQL文件最上方,必须有两行注释。Liquibase会解析这两行注释。

--liquibase formatted sql
--changeset <author name>:<a unique identifier for the SQL changeset>

第一行是固定写法,代表这个SQL文件是Liquibase使用。
第二行是指定作者和SQL文件的唯一编码,用冒号区隔。

推荐作者使用自己的邮箱,唯一编码直接定义为SQL文件的名称。

注:唯一编码不允许重复。

DDL和DML分开不同文件。

DDL例子:
image-1669874614439

DML例子:
image-1669874663480

4.2 查看SQL脚本执行结果

将文件都配置好以后,启动工程,Liquibase会自行寻找全部的待执行SQL,并和当前配置的数据库链接中的库进行适配,将没有执行的SQL按照顺序执行。

如果SQL存在问题执行失败,则工程不会启动成功。

Liquibase会在数据库中创建两张表databasechangelog和databasechangeloglock。
image-1669874717462
我们可以看到databasechangelog中保存了我们脚本的执行记录,只有成功执行的脚本会记录到这个表中。

可以看到ID字段是我们在SQL文件写的注释第二行唯一编码,AUTHOR字段是注释第二行作者。
image-1669874726048

五、建议与附录

5.1 项目落地建议

  • 业务服务必须使用Liquibase初始化数据库结构。
  • 变更数据库结构时,必须使用Liquibase进行管理。
  • 不得手工更改数据库结构,即使是测试环境。
  • DDL和DML必须严格区分,不得混写在一个SQL脚本中。

5.2 附录