文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

聊聊多版本业务模型设计

2024-11-30 18:01

关注

最近业务上用到比较多的多版本场景。这里总结一下多版本业务模型设计的思路。

多版本需求梳理

先梳理一下多版本的一般诉求:

  1. 同一个数据经过多次编辑后,会产生多个版本,其中历史版本不能删除掉,因为可能有上下游在使用;
  2. 多版本通常用于配置中,最新一个版本的配置通常可以多次修改、测试,确定后再发布;
  3. 已经发布的历史版本不能随便修改,因为有数据在使用;
  4. 在消费侧,一般默认是使用最新已发布的版本;
  5. 多版本可能会有发布审批、与上一个版本的diff等需求场景;

多版本状态机设计

一个多版本的业务模型,通常会有以下的状态机。其中“废弃”不是必须的,回滚操作也不是必须的(回滚操作会给代码和表设计带来很大的复杂性),发布中间可能会有发布中、审批中等状态。

草稿可以在原版本编辑,但已发布的数据再编辑,就会生成一个新版本的草稿。

有时候也会有下线操作,这个时候所有版本的状态就会被改为“已下线”。

多版本表设计

对于多版本而言,你需要有一个唯一标识这个业务数据的字段,可以叫id​或者code。

同时,需要一个字段来标识版本,这个版本建议是一个递增的数字,叫version​。有些业务期望版本是业务输入的,或者有一个版本说明的概念,那可以新增一个字段叫version_desc。

我们可以把唯一标识和版本拼接起来,作为这个数据在这个版本的唯一键,可以叫code_version​。通常是拼接成一个字符串,中间用某种特定的分隔符来区分,比如#​。那code_version​可能就长这样:A12334#3​。这里就要求code​里面不能有分隔符#,不然代码逻辑处理起来就比较麻烦。

这里说一下这个拼接字段的必要性,因为上下游往往会存code + version。那上下游在列表查询等场景来查询数据的时候,如果没有这个字段,只能循环一个个查,不能用where批量查询。

另外一个必要的字段就是status来标识当前版本的状态。

还有一个非必须的字段is_last_version​,用来标识当前这条数据是不是它的最新版本,无论是草稿态还是已发布还是已废弃,它都会变成true。这里在待会儿下文的查询要点中会解释它的用处。如果不用这个字段也能查,但是需要group by order,整体查询语句麻烦,效率低。在写的时候多维护一下这个数据,会让查询的时候方便很多。

其它的都是审计字段了。最终的建表语句可能长这样:

CREATE TABLE `t_xxx`  
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`code` varchar(255) NOT NULL DEFAULT '' COMMENT 'code',
`version` int NOT NULL DEFAULT 0 COMMENT '版本',
`version_desc` varchar(255) NOT NULL DEFAULT '' COMMENT '版本说明',
`code_version` varchar(255) NOT NULL DEFAULT '' COMMENT 'code和版本',
`is_last_version` tinyint NOT NULL DEFAULT '0',
`status` varchar(255) NOT NULL DEFAULT '' COMMENT '状态',
# 以下是业务字段...
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '名称',

# 以下是审计字段...
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_by` varchar(10) NOT NULL DEFAULT '' COMMENT '创建人',
`modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`modify_by` varchar(10) NOT NULL DEFAULT '' COMMENT '修改人',
`deleted_at` bigint DEFAULT '0' COMMENT '删除时间秒时间戳',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_code_version_deleted_at` (`code`, `version`, `deleted_at`)
) ENGINE = InnoDB
AUTO_INCREMENT = 5
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci COMMENT ='xxx表'

生产端和消费端的查询要点

生产端就是配置数据的地方,消费端就是使用的地方。生产端和消费端有一些区别,生产端往往要看最新的版本,包括草稿等状态,还要能修改。而消费端一般只用最新已发布的版本。

生产端

生产端的查询,可以按照is_last_version为true来过滤,这样就只查每一个code的最新版本的数据。

同时,每个code也应该返回一个version​列表,是这个数据code_version的集合,以便用户查看和跳转历史版本。

生产端的写入,需要维护好状态、版本、is_last_version等字段。在编辑的时候,要判断当前的状态是草稿态还是已发布,如果是已发布,是要创建一条新的记录(当然这个在前端判断也是可以的,但后端要做好校验,防止页面没刷新等场景造成脏数据)。

消费端

消费端的查询,需要查询最新已发布版本,一般是通过状态来过滤,比如status = Online。

但这里根据状态过滤有一个问题:历史已发布的版本怎么办?如果一个code发布了3个版本,那岂不是会查出来3条数据?要解决这个办法有两种思路:

我个人比较喜欢用第一种方案,少维护一个字段,仅仅多维护一个枚举就行了。

其它注意事项

上下游

我们在上下游的接口交互中,除了要根据code​查最新已发布版本这种消费端场景外,通常用code_version来交互。这样在DB中可以直接命中一条数据,查询起来也方便。

这个数据和其他数据的关系,也通常使用code_version来存,因为不同版本关联的数据可能不同。

diff

diff往往是利用领域模型json化后来diff。这里的diff能力可以做成一个通用的服务,传入old json和new json,返回哪些是新增的,哪些是删除的,哪些是变更的。内部的逻辑一般是利用json_path和递归的方法来做。

diff的难点是做成配置化,配置哪些属性参与diff,哪些属性ignore diff。diff出来之后,可能枚举等需要key转换成label,外部有一个转换函数,或者前端去转。

另一块需要注意的就是数组的顺序。有些字段虽然到json是数组,但业务上本身是顺序无关的,这种数据的比对会更麻烦一些。

回滚

回滚其实很麻烦,包括已发布的回滚到上一个版本、发布中的回滚到草稿态。主要是前者很麻烦,尤其是有上下游使用了这个版本的数据,一般是不允许轻易回滚的。

如果有这类场景,多半是没有上下游,比如服务发布、应用发布等。这种回滚,当前版本的数据一般也不会删除,而是设置成一个特殊的状态。下次编辑上一个版本的时候,生成的version也不是+1, 而是+2甚至是+n,还得查一遍库,比较麻烦。

所以如果不是有特殊的需求,可以不做已发布的回滚,它会带来很多复杂性。

来源:编了个程内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯