〇、数据库版本变更管理惨烈现状
开发环境、测试环境、生成环境同时存在多个数据库副本。
代码我们使用Git或者SVN能很好的管理版本,但是数据库呢?脚本呢?
不幸的是,我们做得并不好。许多项目仍然依赖于手动执行的SQL脚本。有时甚至没有(编写临时的SQL语句来解决问题)。
很快就会出现许多问题:
这台机器上的数据库处于什么状态?
某个SQL脚本是否已应用?
生产中的快速修复SQL是否在之后的测试环境中执行过?
如何创建一个新的数据库实例?
这些问题的答案往往是:我们不知道。
讲一个笑话:暴雪要重置60级经典版本魔兽世界,代码能找到、模型文件能找到、唯独当年版本的数据库找不到了。
一、技术选型Flyway和Liquibase
目前做数据库变更管理的Java开源库,做得好的就是Flyway和Liquibase。
下面我们比较一下这两个库的特性:
在我的实际使用中发现,Flyway 存在几个严重问题:
- 最新社区版flyway仅支持5年内发布的的数据库版本,比如MySQL仅支持到8.0。
- blob大字段不能导入。
- 复杂数据(比如带转义符号和尖括号等数据)不能导入的问题。
在Liquibase中,以上三个问题均不存在。
二、Liquibase介绍
Liquibase 是用于数据库重构、管理、记录变化与回滚的开源工具。 在写代码的时候,我们使用 Git 或 subversion 对代码进行版本控制,在数据库中,我们可以使用 liquibase 对数据库表进行版本控制。
持续维护
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.
2.使用 springboot 注解 @Configuration
3.3 配置SQL文件执行索引
1.在resources/db/changelog下创建DDL和DML文件夹,将我们的数据库脚本放入其中。
2.编辑db.changelog-master.yaml文件,将SQL文件地址写入,Liquibase会在工程启动时,按照顺序执行。
四、使用
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例子:
DML例子:
4.2 查看SQL脚本执行结果
将文件都配置好以后,启动工程,Liquibase会自行寻找全部的待执行SQL,并和当前配置的数据库链接中的库进行适配,将没有执行的SQL按照顺序执行。
如果SQL存在问题执行失败,则工程不会启动成功。
Liquibase会在数据库中创建两张表databasechangelog和databasechangeloglock。
我们可以看到databasechangelog中保存了我们脚本的执行记录,只有成功执行的脚本会记录到这个表中。
可以看到ID字段是我们在SQL文件写的注释第二行唯一编码,AUTHOR字段是注释第二行作者。
五、建议与附录
5.1 项目落地建议
- 业务服务必须使用Liquibase初始化数据库结构。
- 变更数据库结构时,必须使用Liquibase进行管理。
- 不得手工更改数据库结构,即使是测试环境。
- DDL和DML必须严格区分,不得混写在一个SQL脚本中。