动态表单存储设计
前言
Flowable, Activiti 等开源解决方案所提供的表单引擎是没有业务表单数据持久化的功能(即自动创建表,将表单数据持久化功能),只提供动态表单创建以及渲染功能。目前来看表单引擎服务主要功能如下:
- 动态表单配置以及渲染(主要在于前端实现)
- 表单数据库持久化
以下是目前实现业务表单数据持久化的几种方案:
以下方案都以请假流程的表单为例,比较简单就请假天数(days)以及请假理由(reason),动态表单如下所示:
方案一:动态添加字段
一个表单对应数据库的一张或多张物理表(主从表)
针对请假流程如何操作呢?给请假流程表单创建一张数据表,包含字段 days
以及 reason
。其他业务表单也是如此操作。
create table leave_data
(
days int default 0 null comment '请假天数',
reason varchar(250) null comment '请假理由'
)
comment '请假流程业务数据';
该方案存在的问题:
- 一个表单对应数据库的一张或多张物理表,随着业务的增多,数据库的物理表会不断膨胀。
- 业务表单字段需要修改时(比如给请假流程添加一个开始时间字段,就需要调整物理表结构),其对应的物理表结构也需要修改,在物理表很多数据时,改变物理表scheme会锁表。
方案二:预留空白字段,动态分配
业务数据存储表:
create table data
(
name varchar(250) null comment '业务表单名',
field_0 varchar(250) null comment '字段0',
field_1 varchar(250) null comment '字段1',
field_2 varchar(250) null comment '字段2',
field_3 varchar(250) null comment '字段3'
)
comment '业务数据';
业务表单属性表:
create table table_config
(
name varchar(250) null comment '表单名',
field_name varchar(250) null comment '字段名',
field_map varchar(250) null comment '字段映射'
)
comment '表配置';
实际操作下来,存储是这样哒:
那么动态字段变更需要修改表字段配置表即可。
缺点:
- 操作数据的时候都需要先去 map 中转以下才能查询(程序层面可以解决)
- 如果一张业务表保存所有的数据话,不利于优化(可以进行扩展,配置多张业务表,不过这样也可能会出现方案一中物理表爆炸的问题)
方案三:属性使用 KEY/VALUE 格式存储
将表单数据全部都用 Key/Value 的格式来存储。参考如下:
create table attributes
(
f_id varchar(250) null comment '关联id',
key varchar(250) null comment '属性',
value varchar(250) null comment '属性值',
field_2 varchar(250) null comment '字段2',
field_3 varchar(250) null comment '字段3'
)
comment '属性';
具体操作后即是:
动态添加属性字段只需要添加 Key/value。题外话,reddit 的数据库就两张表,也是这样的设计方案,不过现在已经改掉了,成为历史。
缺点:
- 不太好支持关联子表
- 程序中处理取值不方便
方案四:MongoDB 方案设计
MongoDB 方案的话,只需要将前端发过来的JSON写入即可,这里还是以请假流程为例:
集合内数据允许动态添加字段:
集合类似于关系型数据库中的表,可以存储不规则的数据,只能说 Mongodb 擅长干这种事情。
总结
以上方案设计生产环境使用还需要改进使用,目前市面上用的多得应该是方案二,MongoDB 也是一个不错选项,仅在数据持久化这块,具体业务场景下使用 MongoDB + 关系型数据库的设计也可以是一个备选的方案。