绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
基于Flyway的数据库版本控制实战
2022-09-08 16:07:03

背景

大家平时在开发过程中,会用Git来进行我们的代码管理。如Git这些,使用这些版本控制系统能轻松的帮我们

  • 解决不同开发人员之间的代码冲突
  • 处理版本回退
  • 实现软件代码的CI/CD等

那大家考虑过么,针对数据库脚本怎么办的呢?有如下几个问题?

  • 我们如何比对多环境的数据库版本是否一致?
  • 几个人同时修改一个表,如何进行协同合作?
  • 我们如何确定该脚本是否在生产环境运行过?

针对上述这些问题,可以通过一些Database migrations工具来进行解决,而Flyway就是其中一种工具!那么,目前为止 介绍flyway的文章,都紧紧的java生态关联在一起了,不具备工程化的能力!因此,才有了本文诞生,可以迅速在生产上搭建出工程化的数据库版本控制工具。

正文

约定

ok,为了避免歧义,我们先达成一些约定,避免后文看着看懵了!我们在开发过程中呢,一般有如下环境:

Dev环境:开发环境,该环境是程序猿们专门用于开发的环境,配置可以比较随意,主要是为了开发调试方便,例如可用来前后端联调等。

Test环境:测试环境,该环境一般为测试人员所用,主要验证我们所实现的功能是否满足我们业务所要求的规格。

Uat环境:用户验收测试环境,该环境一般为真实用户所用,例如你是给XX企业开发的系统,那么该环境就是给XX企业的人员进行验收测试环境

Staging环境:预发布环境,该环境一般是生产环境的镜像环境, 测试人员在Staging 环境上对新版本做后一轮验证, 通过后才能deploy到生产环境上

Prd环境:生产环境,该环境是正式提供对外服务的环境。

那么我们在开发过程中,在各个环境有对应分支,每次对应分支的代码变动时,Jenkins流水线会自动触发,将对应的分支代码Build到对应的环境上。一般情况下,Dev环境对应的就是Dev分支,Test环境对应的就是Test分支,。。。而Staging环境和Prd环境,对应的是基于master分支拉出的版本分支。

一般来说,版本分支有三位版本号,如1.3.0,位代表重大变更,例如涉及到代码框架替换这种级别的变更,改位。每次功能发布,改第二位。每次有紧急BugFix版本,改第三位~可能不同公司有不同的规范,但是这和本文关系不大。

那么开发流程一般如下



ok,到上面为止,都是大家懂的一些常识,可能流程上不同公司会有一些不大一样,例如有的公司上test环境,一定是从dev分支合过去,并不是从feature分支来合。大家在落地过程中,可以按照自己公司的流程进行对应修改,当然这并不影响后文阅读。

下面我们简单的介绍一下Flyway,不墨迹,几句话就能讲明白!

Flyway原理

Flyway在官网上提供了多种执行方式,但是我们要在项目中工程化的使用,我只推荐一种,就是命令行的方式~

那么,我只教一个命令就行了,只需要会这个命令,就能在项目中搭建出工程化的数据库版本控制工具。(画外音:么错,孤独烟老师就是这么diao,一个命令就能搞定一切~)

flyway -configFiles=config/flyway.conf migrate

flyway.conf文件里头放的就是一些db的配置,主要是长这样的

flyway.driver=org.hsqldb.jdbcDriver
flyway.url=jdbc:hsqldb:file:/db/flyway_sample
flyway.user=SA
flyway.password=mySecretPwd
flyway.locations=database/migrations

懂的人一看就知道,前面四个是数据库驱动的配置,第五个是sql脚本的位置!那么这个配置的含义就是,用前面四个配置连上数据库,然后执行sql脚本,就能操作数据库写入数据库~

Flyway的执行原理,我用大白话来说明一下,有如下几步:

  • (1)FLyway会在数据库中创建一个flyway_schema_history的表,用于记录数据库当前的版本。
  • (2)执行flyway migrate命令,根据config/flyway.conf配置中的连接信息连接到数据库。
  • (3)检查指定目录下的sql文件,查找符合flyway命令格式的文件,然后比较这些sql文件的版本,如果sql文件版本比实际数据库中flyway_schema_history表里记录的版本要低,则执行升级版本的sql文件。
  • (4)执行成功后,则更新flyway_schema_history表中记录。

ok,看到这里,你一定要问我两个问题~~

  • (1)什么是符合flyway命令格式的文件?
  • (2)什么是sql文件的版本,sql文件还有版本这个概念么?

我们看一张图



只要你在脚本文件夹下,建立符合上述规范的文件,flyway就会将其认为是有效文件,从而执行。例如文件名可以是V2.1__init_request.sql . 注意:version和descprition之间的分割符是双下划线__

但是,孤独烟老师不得不说一句了!我们实战中文件不这么命名,因为这么命名,维护起来不方便。

其实,我们这些sql文件也是有规范的~可以像下面这么叫

V{version}_{date}_{num}__{type}_{description}_{Author}.sql

例如V1_0_0_20220418_1__DDL_alter_table_medicinenames_guduyan.sql


当然,你不守这个规范,也是可以的。只是这么做,以后维护起来方便而已~

在这里

  • version : 每次发版的项目版本号,参考我上面提到的项目版本号的概念呢,_会翻译为小数点,1_0_0 即为项目1.0.0 版本
  • date: 提交日期2022年4月18日
  • num: 开发人员自由命名,格式必须为数字,主要是为了防止有同版本文件文件出现
  • type: sql文件类型 DML 数据更新(插入、更新、删除); DDL 结构更新; DCL 权限控制;
  • description: 文件描述
  • Author: 开发人员姓名

注意了,这种命名规范下,有两个版本的概念,一个是sql文件的版本,一个是项目的版本。我用一张图来对比一下



也就是说sql文件的版本是1.0.0.20220418.1(_会翻译为小数点),项目的版本是1.0.0

当然,可能这里你们会有点懵,来来来,孤独烟老师打个实战比方,一点就通! 打个比方: 假设今天是2022年4月18日,孤独烟老师要发布一个1.0.0项目的sql脚本~

这个项目对于数据库的改动,刚好要创建一个person_tab,并且初始化两条数据在里头~

因此只要在对应的脚本目录下,准备两个文件时,分别是: V1_0_0_20220418_1__DDL_create_person_table_guduyan.sql 内容为

CREATE TABLE Person_table(
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    Feature varchar(255)
);

V1_0_0_20220418_2__DML_insert_person_table_guduyan.sql 内容为

INSERT INTO Person_table
(PersonID, LastName, FirstName, Address, Feature)
VALUES(1, '烟', '孤独', NULL, '帅');
INSERT INTO Person_table
(PersonID, LastName, FirstName, Address, Feature)
VALUES(2, '雄', '周', NULL, '非常帅');

执行命令

flyway migrate

此时呢,就会连上对应数据库,与flyway_schema_history的表中数据对比,判断则两个sql是否在该数据库中执行过,发现没有,则执行sql脚本,创建表,并且插入两条数据。执行完结果如下~

Person_table表的数据为


flyway_schema_history表的数据为

看到这里,回忆一下我们的规范

 V{version}_{date}_{num}__{type}_{description}_{Author}.sql

能明白为什么有{num}位了么,因为如果没有该位,sql版本就是1.0.0.20220418,此时容易产生冲突,总不可能一天就一份sql文件吧?因此在后面再带一位编号~ 当然,各公司可能有自己的规范,按照各自规范实现即可~

ok,有了上面的基础知识,可以来说说说项目中如何使用了(这才是实战经验)~

项目中使用

实战中,我们往往不单独用Flyway,必定是和Jenkins一起用~

大家莫急,听我细细到来~

假设,我们有一个仓库,专门放项目的sql脚本的,推荐仓库名这么命名~

{项目名}-database-flyway

我们姑且认为这个项目叫guduyan,那么这个仓库名字就是guduyan-database-flyway,仓库下目录结构如下

guduyan-database-flyway
├── config
│   ├── Jenkinsfile
│   ├── flyway.conf
├── README.md
└── sql
    ├─V1_0_0_20220418_1__DDL_create_person_table_guduyan.sql
    ├─V1_0_0_20220418_2__DML_insert_person_table_guduyan.sql

当然,分支和我们的项目一样,有dev分支,test分支等~提交sql流程,和我们提交项目代码流程类似,不赘述~

Jenkins上我们需要配置一个多任务流水线,可以监听各个分支的变更,然后执行

Jenkinsfile

里头的pipeline脚本,去操作对应环境的数据库,执行flyway命令~

后,我们不要忘了在gitlab上配一个Hook,这样代码发生变更,才能通知到jenkins。

(可能会有人觉得这里写的比较简单,木有图,我只想说,我又不是教你jenkins怎么用,讲思路就行了~但凡配过jenkins的,基本都能get到我在说啥~)

那么,我们在提交sql脚本的时候,例如从feature分支,合并到dev分支~

我们把代码提交到feature分支后,发起一个从feature分支到dev的Merge Request,由对应人员Merge代码以后,Gitlab可以自动通知jenkins进行build操作,然后对应 style="margin: 1.4em 0px; color: rgb(18, 18, 18); font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">具体如下图所示


总结

写到这里,基本上将Flyway工程化的套路讲完了!那么,接下来思考两个问题 - (1)已经上线的项目,数据库里已经有大量表,如何接入Flyway进行管理? - (2)如果我在Test环境执行了脚本,上到Uat后,发现这个脚本在Uat执行有风险,如何回滚?

后,谢谢大家阅读~~

分享好友

分享这个小栈给你的朋友们,一起进步吧。

IT基础架构
创建时间:2020-06-17 15:29:51
IT基础架构是相对于IT应用架构而言的,指的是为了各种应用系统能够顺利、可靠地运行,而提供的一系列硬件、软件的集合体。正是因为有了这些IT基础架构的各种设施,IT应用架构才能运行并提供服务。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 栈栈
    专家
戳我,来吐槽~