数据库初始化
我们知道,代码可以通过版本管理工具来进行管理。那 sql 呢,同样也是可以的。但为什么要这么做呢,因为我们在项目或产品开发过程中,很难再一开始就把业务理清楚,把数据库表设计好,因此数据表也会在开发周期中不断迭代。尤其是对于已上线的应用来说,这个版本新增了多少字段,或是修改了多少条数据,如果这些数据没有去存档,等到上线时,测试反馈 bug 时,我们查日志才发现原来是漏了某个字段未发布等等似曾相识的问题。那我们怎么去规避呢?
flyway 介绍
flyway 是一款开源的数据库版本管理工具。它可以很方便的在命令行中使用,或者在 Java 应用程序中引入,用于管理我们的数据库版本。 那通过它我们怎么有效的来规避这些问题呢?
标品里怎么做的
打开标品项目模块,里面有个 sql 文件夹,有以下文件:
- generator.sql 代码生成器 sql,如果不用可忽略,手动执行
- V2.3.0__create_table.sql 标品业务 2.3 sql
- V2.4.0__create_table.sql 标品业务 2.4 sql
- V99.0.0__init_data.sql 标品业务初始数据 sql
这个命名有什么规则吗?有的。Vx.x.x__xx.sql 形如这种格式。非这种格式的将会被忽略。
flyway 会根据版本号递增去执行脚本,执行成功会生成flyway_schema_history
表。其中的 version 字段记录的便是 Vx.x.x 值。
多次执行脚本不会重复执行,他的依据是文件内容 md5,也就是你如果改动了某个版本 sql,但同时与存档的文件内容 md5 比对不正确后,将会报错。
那我们应该如何去调整呢?两种方式:
- 删除
flyway_schema_history
表里最新一条版本号执行记录,然后再修改对应版本 sql,再重新执行 - 重新递增一个版本号,书写最新的内容,用于调整之前的问题
再开发阶段,比较推荐第一种。后续进入业务周期迭代时,比较推荐第二种。
好了,这样做了,有什么好处?
有什么好处
- 关于数据库的任何改动我们都有 sql 文件记录,好处不用多说
- sql 文件执行自备自动化能力,这个对于部署来说简直不要太友好
标品里是如何落地的
在 framework-generator 模块 util 文件夹下有个DbMigrateUtil
,打开看下核心代码:
/**
* 数据库迁移。
*
* @author mjyang
* @date 2023/7/26 18:04
*/
public class DbMigrateUtil {
public static void main(String[] args) {
// 配置 host,dbName,user,password 运行便会自动执行 sql 文件下 V 打头的 sql 文件。
String host = "xx.xx.xx.xx:xx";
String dbName = "xx_test";
String url = "jdbc:mysql://" + host + "/" + dbName + "?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=true&serverTimezone=Asia/Shanghai";
String user = "root";
String password = "123456";
Flyway flyway = Flyway
.configure()
.locations("filesystem:sql")
.ignorePendingMigrations(true)
.dataSource(url, user, password)
.target(MigrationVersion.LATEST)
.baselineOnMigrate(true)
.validateOnMigrate(true)
.load();
flyway.validate();
flyway.migrate();
}
}
核心代码也就是这么几行。修改对应的数据库参数,运行起来,便会发现,它自动帮我们创建好了数据库。
写在最后
但是你会发现,为什么这里的手动运行和前面说的自动化运行不一样呢?这是因为考虑到多人协作下,如果开发人员不固定的情况下,人员频繁更换,且开发习惯如果没有调整到文件先行的话,这个自动化运行可能会带来副作用。想一下,我通过 navicat 直接修改不是更快吗?因此选择了手动运行的方式。那它的价值又是什么呢?它的最大价值便是在于提供标准化的 sql 版本管理,让我们更加专业,版本上线更稳。