如何存储数据字典?
解读
在国内的 CouchDB 面试中,面试官问“如何存储数据字典”并不是想听“把字典转成 JSON 塞进去”这么简单,而是考察候选人能否把业务语义、版本管理、离线同步、权限隔离、热更新这五个核心痛点一次性闭环。数据字典(下拉选项、码表、枚举、配置项)虽然体量小,却是交易单据、审批流、报表统计的“锚点”,一旦不同节点出现版本分叉,会直接造成业务数据漂移,这是金融、政务、零售等行业验收的红线。因此,回答必须体现“离线优先 + 多主复制”场景下的确定性方案。
知识点
- CouchDB 文档模型:JSON 文档自带
_id、_rev,天然支持多版本合并,适合字典“键-值-描述-状态”四维结构。 - 设计文档(_design):可编程存储 + 视图过滤,能把字典当“配置服务”用,避免额外接口。
- 复制过滤器:
_selector或filter函数,可让移动端只拉取“本业务线 + 已启用”的字典,节省 70% 流量。 - 本地优先策略:PouchDB 离线缓存字典,
_rev作为版本令牌,应用层用revpos做增量 diff,实现秒级热更新。 - 权限隔离:CouchDB 的
_security对象支持数据库级 ACL,结合validate_doc_update可做到“运营人员可改,业务系统只读”,符合国内等保要求。 - 灰度发布:利用
_replicator数据库的doc_ids数组,先复制 5% 节点验证,再全量推送,降低生产事故。
答案
我采用“一库一类一分支”的三层模型:
- 独立建库
dict_v1,_id规则固定为type:code:version,例如gender:1:20240518,保证全局唯一且可排序。 - 每条字典文档除
value、label外,显式写入scope、status、effectiveFrom、effectiveTo,方便视图做时间窗过滤。 - 在设计文档
_design/dict中预置两个视图:byType:以type为 key,返回最新_rev,用于移动端增量比对;active:以[type, status, effectiveFrom]为复合 key,只输出status="A" && now() between effectiveFrom-To的记录,屏蔽未生效或已失效项。
- 复制阶段,移动端带
filter=app/dict_active,只同步 200KB 以内的热数据;后台运营库通过validate_doc_update拒绝非白名单用户修改,确保字典源唯一可信。 - 版本升级时,不删除旧文档,而是插入新版本并原子切换
status,利用_rev冲突机制自动合并,零停机完成热更新。 - 最后在
_replicator数据库写入灰度任务,先复制到dict_v1_gray验证业务正确性,再全量推送,符合国内金融变更评审流程。
拓展思考
如果字典体量膨胀到 10 万条以上,或者需要跨租户隔离,可把“一库一类”升级为“一租户一设计文档”:
- 利用 CouchDB 3.x 的分片功能,把字典库按
tenantId做哈希分片,避免单节点热点; - 在
validate_doc_update里加入tenantId与userCtx.roles的匹配逻辑,实现行级多租户; - 对超大体量字典,启用
text索引(CouchDB 内置 Lucene 插件),把label字段做全文检索,毫秒级返回模糊匹配结果; - 若业务要求秒级广播,可监听
_changes?feed=eventsource,用 Server-Sent Events 推送到前端,替代轮询,在政企内网场景下比 WebSocket 更易过防火墙。