自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊多版本業(yè)務(wù)模型設(shè)計(jì)

開(kāi)發(fā) 前端
回滾其實(shí)很麻煩,包括已發(fā)布的回滾到上一個(gè)版本、發(fā)布中的回滾到草稿態(tài)。主要是前者很麻煩,尤其是有上下游使用了這個(gè)版本的數(shù)據(jù),一般是不允許輕易回滾的。

 本文轉(zhuǎn)載自微信公眾號(hào)「編了個(gè)程」,作者Yasin x 。轉(zhuǎn)載本文請(qǐng)聯(lián)編了個(gè)程公眾號(hào)。

最近業(yè)務(wù)上用到比較多的多版本場(chǎng)景。這里總結(jié)一下多版本業(yè)務(wù)模型設(shè)計(jì)的思路。

多版本需求梳理

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

  1. 同一個(gè)數(shù)據(jù)經(jīng)過(guò)多次編輯后,會(huì)產(chǎn)生多個(gè)版本,其中歷史版本不能刪除掉,因?yàn)榭赡苡猩舷掠卧谑褂茫?/li>
  2. 多版本通常用于配置中,最新一個(gè)版本的配置通??梢远啻涡薷?、測(cè)試,確定后再發(fā)布;
  3. 已經(jīng)發(fā)布的歷史版本不能隨便修改,因?yàn)橛袛?shù)據(jù)在使用;
  4. 在消費(fèi)側(cè),一般默認(rèn)是使用最新已發(fā)布的版本;
  5. 多版本可能會(huì)有發(fā)布審批、與上一個(gè)版本的diff等需求場(chǎng)景;

多版本狀態(tài)機(jī)設(shè)計(jì)

一個(gè)多版本的業(yè)務(wù)模型,通常會(huì)有以下的狀態(tài)機(jī)。其中“廢棄”不是必須的,回滾操作也不是必須的(回滾操作會(huì)給代碼和表設(shè)計(jì)帶來(lái)很大的復(fù)雜性),發(fā)布中間可能會(huì)有發(fā)布中、審批中等狀態(tài)。

草稿可以在原版本編輯,但已發(fā)布的數(shù)據(jù)再編輯,就會(huì)生成一個(gè)新版本的草稿。

圖片

有時(shí)候也會(huì)有下線操作,這個(gè)時(shí)候所有版本的狀態(tài)就會(huì)被改為“已下線”。

多版本表設(shè)計(jì)

對(duì)于多版本而言,你需要有一個(gè)唯一標(biāo)識(shí)這個(gè)業(yè)務(wù)數(shù)據(jù)的字段,可以叫id?或者code。

同時(shí),需要一個(gè)字段來(lái)標(biāo)識(shí)版本,這個(gè)版本建議是一個(gè)遞增的數(shù)字,叫version?。有些業(yè)務(wù)期望版本是業(yè)務(wù)輸入的,或者有一個(gè)版本說(shuō)明的概念,那可以新增一個(gè)字段叫version_desc。

我們可以把唯一標(biāo)識(shí)和版本拼接起來(lái),作為這個(gè)數(shù)據(jù)在這個(gè)版本的唯一鍵,可以叫code_version?。通常是拼接成一個(gè)字符串,中間用某種特定的分隔符來(lái)區(qū)分,比如#?。那code_version?可能就長(zhǎng)這樣:A12334#3?。這里就要求code?里面不能有分隔符#,不然代碼邏輯處理起來(lái)就比較麻煩。

這里說(shuō)一下這個(gè)拼接字段的必要性,因?yàn)樯舷掠瓮鶗?huì)存code + version。那上下游在列表查詢等場(chǎng)景來(lái)查詢數(shù)據(jù)的時(shí)候,如果沒(méi)有這個(gè)字段,只能循環(huán)一個(gè)個(gè)查,不能用where批量查詢。

另外一個(gè)必要的字段就是status來(lái)標(biāo)識(shí)當(dāng)前版本的狀態(tài)。

還有一個(gè)非必須的字段is_last_version?,用來(lái)標(biāo)識(shí)當(dāng)前這條數(shù)據(jù)是不是它的最新版本,無(wú)論是草稿態(tài)還是已發(fā)布還是已廢棄,它都會(huì)變成true。這里在待會(huì)兒下文的查詢要點(diǎn)中會(huì)解釋它的用處。如果不用這個(gè)字段也能查,但是需要group by order,整體查詢語(yǔ)句麻煩,效率低。在寫的時(shí)候多維護(hù)一下這個(gè)數(shù)據(jù),會(huì)讓查詢的時(shí)候方便很多。

其它的都是審計(jì)字段了。最終的建表語(yǔ)句可能長(zhǎng)這樣:

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 '版本說(shuō)明',
`code_version` varchar(255) NOT NULL DEFAULT '' COMMENT 'code和版本',
`is_last_version` tinyint NOT NULL DEFAULT '0',
`status` varchar(255) NOT NULL DEFAULT '' COMMENT '狀態(tài)',
# 以下是業(yè)務(wù)字段...
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '名稱',

# 以下是審計(jì)字段...
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`create_by` varchar(10) NOT NULL DEFAULT '' COMMENT '創(chuàng)建人',
`modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時(shí)間',
`modify_by` varchar(10) NOT NULL DEFAULT '' COMMENT '修改人',
`deleted_at` bigint DEFAULT '0' COMMENT '刪除時(shí)間秒時(shí)間戳',
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表'

生產(chǎn)端和消費(fèi)端的查詢要點(diǎn)

生產(chǎn)端就是配置數(shù)據(jù)的地方,消費(fèi)端就是使用的地方。生產(chǎn)端和消費(fèi)端有一些區(qū)別,生產(chǎn)端往往要看最新的版本,包括草稿等狀態(tài),還要能修改。而消費(fèi)端一般只用最新已發(fā)布的版本。

生產(chǎn)端

生產(chǎn)端的查詢,可以按照is_last_version為true來(lái)過(guò)濾,這樣就只查每一個(gè)code的最新版本的數(shù)據(jù)。

同時(shí),每個(gè)code也應(yīng)該返回一個(gè)version?列表,是這個(gè)數(shù)據(jù)code_version的集合,以便用戶查看和跳轉(zhuǎn)歷史版本。

生產(chǎn)端的寫入,需要維護(hù)好狀態(tài)、版本、is_last_version等字段。在編輯的時(shí)候,要判斷當(dāng)前的狀態(tài)是草稿態(tài)還是已發(fā)布,如果是已發(fā)布,是要?jiǎng)?chuàng)建一條新的記錄(當(dāng)然這個(gè)在前端判斷也是可以的,但后端要做好校驗(yàn),防止頁(yè)面沒(méi)刷新等場(chǎng)景造成臟數(shù)據(jù))。

消費(fèi)端

消費(fèi)端的查詢,需要查詢最新已發(fā)布版本,一般是通過(guò)狀態(tài)來(lái)過(guò)濾,比如status = Online。

但這里根據(jù)狀態(tài)過(guò)濾有一個(gè)問(wèn)題:歷史已發(fā)布的版本怎么辦?如果一個(gè)code發(fā)布了3個(gè)版本,那豈不是會(huì)查出來(lái)3條數(shù)據(jù)?要解決這個(gè)辦法有兩種思路:

  • 狀態(tài)機(jī)添加一個(gè)Online_history的狀態(tài),在寫入的時(shí)候維護(hù)這種狀態(tài);
  • 表增加一個(gè)is_last_online_version,在寫入的時(shí)候維護(hù)這個(gè)字段;

我個(gè)人比較喜歡用第一種方案,少維護(hù)一個(gè)字段,僅僅多維護(hù)一個(gè)枚舉就行了。

其它注意事項(xiàng)

上下游

我們?cè)谏舷掠蔚慕涌诮换ブ校艘鶕?jù)code?查最新已發(fā)布版本這種消費(fèi)端場(chǎng)景外,通常用code_version來(lái)交互。這樣在DB中可以直接命中一條數(shù)據(jù),查詢起來(lái)也方便。

這個(gè)數(shù)據(jù)和其他數(shù)據(jù)的關(guān)系,也通常使用code_version來(lái)存,因?yàn)椴煌姹娟P(guān)聯(lián)的數(shù)據(jù)可能不同。

diff

diff往往是利用領(lǐng)域模型json化后來(lái)diff。這里的diff能力可以做成一個(gè)通用的服務(wù),傳入old json和new json,返回哪些是新增的,哪些是刪除的,哪些是變更的。內(nèi)部的邏輯一般是利用json_path和遞歸的方法來(lái)做。

diff的難點(diǎn)是做成配置化,配置哪些屬性參與diff,哪些屬性ignore diff。diff出來(lái)之后,可能枚舉等需要key轉(zhuǎn)換成label,外部有一個(gè)轉(zhuǎn)換函數(shù),或者前端去轉(zhuǎn)。

另一塊需要注意的就是數(shù)組的順序。有些字段雖然到j(luò)son是數(shù)組,但業(yè)務(wù)上本身是順序無(wú)關(guān)的,這種數(shù)據(jù)的比對(duì)會(huì)更麻煩一些。

回滾

回滾其實(shí)很麻煩,包括已發(fā)布的回滾到上一個(gè)版本、發(fā)布中的回滾到草稿態(tài)。主要是前者很麻煩,尤其是有上下游使用了這個(gè)版本的數(shù)據(jù),一般是不允許輕易回滾的。

如果有這類場(chǎng)景,多半是沒(méi)有上下游,比如服務(wù)發(fā)布、應(yīng)用發(fā)布等。這種回滾,當(dāng)前版本的數(shù)據(jù)一般也不會(huì)刪除,而是設(shè)置成一個(gè)特殊的狀態(tài)。下次編輯上一個(gè)版本的時(shí)候,生成的version也不是+1, 而是+2甚至是+n,還得查一遍庫(kù),比較麻煩。

所以如果不是有特殊的需求,可以不做已發(fā)布的回滾,它會(huì)帶來(lái)很多復(fù)雜性。

責(zé)任編輯:武曉燕 來(lái)源: 編了個(gè)程
相關(guān)推薦

2023-02-10 08:59:42

業(yè)務(wù)技術(shù)核心

2023-11-27 07:57:46

2024-04-26 00:28:14

異地多活架構(gòu)

2023-11-28 07:45:48

Rust自動(dòng)化測(cè)試

2022-08-16 08:17:09

CDPCRM數(shù)據(jù)

2022-01-10 08:17:40

異地設(shè)計(jì)實(shí)踐

2012-12-03 13:50:40

IBMdW

2021-01-31 23:54:23

數(shù)倉(cāng)模型

2020-04-01 10:48:28

業(yè)務(wù)設(shè)計(jì)架構(gòu)模型CIO

2021-10-09 07:55:49

設(shè)計(jì)師業(yè)務(wù)用戶需求

2024-10-06 12:56:36

Golang策略設(shè)計(jì)模式

2022-05-02 21:47:13

并發(fā)編程線程

2023-11-06 08:26:11

Spring微服務(wù)架構(gòu)

2024-04-17 08:03:45

架構(gòu)設(shè)計(jì)Java

2009-01-20 09:22:09

NGN下一代網(wǎng)絡(luò)電信

2022-05-18 08:05:20

pyenvPython解釋器

2022-10-09 08:15:14

算法智能運(yùn)維

2024-09-13 16:47:06

模型量化AI

2023-12-06 19:04:31

多平臺(tái)消息推送

2024-10-14 14:28:19

支付系統(tǒng)設(shè)計(jì)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)