十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
本文轉(zhuǎn)載自微信公眾號「編了個(gè)程」,作者Yasin x 。轉(zhuǎn)載本文請聯(lián)編了個(gè)程公眾號。

成都做網(wǎng)站、成都網(wǎng)站制作介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。成都創(chuàng)新互聯(lián)擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。
最近業(yè)務(wù)上用到比較多的多版本場景。這里總結(jié)一下多版本業(yè)務(wù)模型設(shè)計(jì)的思路。
先梳理一下多版本的一般訴求:
一個(gè)多版本的業(yè)務(wù)模型,通常會(huì)有以下的狀態(tài)機(jī)。其中“廢棄”不是必須的,回滾操作也不是必須的(回滾操作會(huì)給代碼和表設(shè)計(jì)帶來很大的復(fù)雜性),發(fā)布中間可能會(huì)有發(fā)布中、審批中等狀態(tài)。
草稿可以在原版本編輯,但已發(fā)布的數(shù)據(jù)再編輯,就會(huì)生成一個(gè)新版本的草稿。
有時(shí)候也會(huì)有下線操作,這個(gè)時(shí)候所有版本的狀態(tài)就會(huì)被改為“已下線”。
對于多版本而言,你需要有一個(gè)唯一標(biāo)識這個(gè)業(yè)務(wù)數(shù)據(jù)的字段,可以叫id?或者code。
同時(shí),需要一個(gè)字段來標(biāo)識版本,這個(gè)版本建議是一個(gè)遞增的數(shù)字,叫version?。有些業(yè)務(wù)期望版本是業(yè)務(wù)輸入的,或者有一個(gè)版本說明的概念,那可以新增一個(gè)字段叫version_desc。
我們可以把唯一標(biāo)識和版本拼接起來,作為這個(gè)數(shù)據(jù)在這個(gè)版本的唯一鍵,可以叫code_version?。通常是拼接成一個(gè)字符串,中間用某種特定的分隔符來區(qū)分,比如#?。那code_version?可能就長這樣:A12334#3?。這里就要求code?里面不能有分隔符#,不然代碼邏輯處理起來就比較麻煩。
這里說一下這個(gè)拼接字段的必要性,因?yàn)樯舷掠瓮鶗?huì)存code + version。那上下游在列表查詢等場景來查詢數(shù)據(jù)的時(shí)候,如果沒有這個(gè)字段,只能循環(huán)一個(gè)個(gè)查,不能用where批量查詢。
另外一個(gè)必要的字段就是status來標(biāo)識當(dāng)前版本的狀態(tài)。
還有一個(gè)非必須的字段is_last_version?,用來標(biāo)識當(dāng)前這條數(shù)據(jù)是不是它的最新版本,無論是草稿態(tài)還是已發(fā)布還是已廢棄,它都會(huì)變成true。這里在待會(huì)兒下文的查詢要點(diǎn)中會(huì)解釋它的用處。如果不用這個(gè)字段也能查,但是需要group by order,整體查詢語句麻煩,效率低。在寫的時(shí)候多維護(hù)一下這個(gè)數(shù)據(jù),會(huì)讓查詢的時(shí)候方便很多。
其它的都是審計(jì)字段了。最終的建表語句可能長這樣:
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 '狀態(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)端就是配置數(shù)據(jù)的地方,消費(fèi)端就是使用的地方。生產(chǎn)端和消費(fèi)端有一些區(qū)別,生產(chǎn)端往往要看最新的版本,包括草稿等狀態(tài),還要能修改。而消費(fèi)端一般只用最新已發(fā)布的版本。
生產(chǎn)端的查詢,可以按照is_last_version為true來過濾,這樣就只查每一個(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),防止頁面沒刷新等場景造成臟數(shù)據(jù))。
消費(fèi)端的查詢,需要查詢最新已發(fā)布版本,一般是通過狀態(tài)來過濾,比如status = Online。
但這里根據(jù)狀態(tài)過濾有一個(gè)問題:歷史已發(fā)布的版本怎么辦?如果一個(gè)code發(fā)布了3個(gè)版本,那豈不是會(huì)查出來3條數(shù)據(jù)?要解決這個(gè)辦法有兩種思路:
我個(gè)人比較喜歡用第一種方案,少維護(hù)一個(gè)字段,僅僅多維護(hù)一個(gè)枚舉就行了。
我們在上下游的接口交互中,除了要根據(jù)code?查最新已發(fā)布版本這種消費(fèi)端場景外,通常用code_version來交互。這樣在DB中可以直接命中一條數(shù)據(jù),查詢起來也方便。
這個(gè)數(shù)據(jù)和其他數(shù)據(jù)的關(guān)系,也通常使用code_version來存,因?yàn)椴煌姹娟P(guān)聯(lián)的數(shù)據(jù)可能不同。
diff往往是利用領(lǐng)域模型json化后來diff。這里的diff能力可以做成一個(gè)通用的服務(wù),傳入old json和new json,返回哪些是新增的,哪些是刪除的,哪些是變更的。內(nèi)部的邏輯一般是利用json_path和遞歸的方法來做。
diff的難點(diǎn)是做成配置化,配置哪些屬性參與diff,哪些屬性ignore diff。diff出來之后,可能枚舉等需要key轉(zhuǎn)換成label,外部有一個(gè)轉(zhuǎn)換函數(shù),或者前端去轉(zhuǎn)。
另一塊需要注意的就是數(shù)組的順序。有些字段雖然到j(luò)son是數(shù)組,但業(yè)務(wù)上本身是順序無關(guān)的,這種數(shù)據(jù)的比對會(huì)更麻煩一些。
回滾其實(shí)很麻煩,包括已發(fā)布的回滾到上一個(gè)版本、發(fā)布中的回滾到草稿態(tài)。主要是前者很麻煩,尤其是有上下游使用了這個(gè)版本的數(shù)據(jù),一般是不允許輕易回滾的。
如果有這類場景,多半是沒有上下游,比如服務(wù)發(fā)布、應(yīng)用發(fā)布等。這種回滾,當(dāng)前版本的數(shù)據(jù)一般也不會(huì)刪除,而是設(shè)置成一個(gè)特殊的狀態(tài)。下次編輯上一個(gè)版本的時(shí)候,生成的version也不是+1, 而是+2甚至是+n,還得查一遍庫,比較麻煩。
所以如果不是有特殊的需求,可以不做已發(fā)布的回滾,它會(huì)帶來很多復(fù)雜性。