在web开发中,我们经常会遇到项目中很多对表单进行自定义,比如说saas应用针对用户自定义表单字段名称,自定义列表名称。 还有更高级自定义,比如说自定义的模块,表单、字段、字段类型、流程等自定义。
提供自定义也是一个系统扩展性的体现,自定义功能的强大自然能适应更多的用户场景。
接下来我们就看看自定义的实现方案通常都有哪些方式。
常见的自定义字段的实现方式分为四种由简到繁,扩展性、复杂性也是逐渐增强的,每个方式各有优劣解决的场景也有所不同,具体往下看。
动态列式存储自定义字段
模型如下
ID | Name | Ext1(性别) | Ext2(地区) | Ext3(手机号) | Ext4(WECAHT) |
---|---|---|---|---|---|
1 | 韩梅梅 | 女 | 河南 | 13700000000 | |
2 | 李雷 | 男 | 北京 | abc |
优点
- 查询效率高。
- 支持关联查询。
缺点
- 需要动态变更表结构,在生产环境中安全性太低。
- 扩展能力一般,有上限。
- 浪费资源,比如说有20个扩展字段,一行只用到2个,其余的18个都要存储null来浪费空间。
- 能解决的场景比较有限。
使用关系型数据库EAV模型进行自定义字段存储
在EAV模型中,对象存储在一个表中会有三种属性描述:实体、属性、值。实体表示一条数据,属性表示实体的具有的特征,值表示实体的特征值。此外,属性可以单独存放在另一个表中,通过外键关联对象与属性的关系。
这种模型带来了数据的灵活性,增加对象的属性不需要动态增加数据表的字段。但是EAV表也有较大的性能问题。通常,EAV表带来的一个问题是当查找多个字段时,需要进行关联查询join, 这样的查询效率比较低。
我们常用的行模型(纵向)存储就是EAV模型实现的一种方式
模型如下
人员表
ID | Name |
---|---|
1 | 韩梅梅 |
2 | 李雷 |
扩展映射(Entities)
Entity | Attribute | Value |
---|---|---|
1 | sex(性别) | 女 |
2 | sex(性别) | 男 |
1 | region(地区) | 河南 |
2 | region(地区) | 北京 |
1 | 123456 | |
2 | abc |
优点
- 扩展能力强
- 理论上增加字段无上限
- 可以支持几乎所有的自定义字段类型的需求
缺点
- 关联查询效率低下
- 需要维护自定义字段与值的关系表
Json格式存储自定义字段
目前,市面上主流的关系型数据库几乎都已经添加对JSON和JSONB的字段的存储,这一特性的升级,增加了非关系型数据库的灵活性和可扩展性,而且保留了关系型数据库在事务处理、复杂对象的存储查询方面的优势,开发和使用也非常简单。
json格式非常丰富,在描述自定义字段的这方面比较适合,可以把一行多列的数据压缩到一个json text内,也比较节省空间,json格式可以无限扩展,还可支持多个自定义字段有不同的格式。
模型如下:
ps.支持以下两种存储方式
(1)
ID | Name | Content |
---|---|---|
1 | 韩梅梅 | {“age”:18, “region”: “上海”} |
2 | 李雷 | {“age”:18, “WECHAT”:123456} |
此方式业务表中只存自定义字段的值, 字段结构(值类型、是否为null等)可存在另外表中,根据业务需求来定。参考专利: 自定义字段的一种实现方式
(2)
ID | Name | Content |
---|---|---|
1 | 韩梅梅 | [{“label”:”年龄”, “filedName”:”age”, “value”: 18}, {“label”: “地区”, “filedName”: “region”, “value”: “上海”}] |
2 | 李雷 | [{“label”:”年龄”, “filedName”:”age”, “value”: 18}, {“label”: “微信号”, “filedName”: “WECHAT”, “value”: 123456}] |
优点:
- 扩展能力强
- 理论上无上限
- 可以支持几乎所有自定义字段的需求
- 无需维护自定义字段与值的关系
缺点
- 数据库需要支持 JSON type, 不建议使用text(解析慢,存储空间大)
- 自定义字段不支持与其他表相同字段进行关联查询
- 自定义字段检索需要通过其他方式,例如搜索引擎、cast类型转化、特殊函数json_extract()等
数据库对Json格式支持情况
数据库对Json类型的支持(最新版本):
- Mysql
- PostgreSQL (json与jsonb的区别)
- MongoDB
数据库对Json类型的检索
- Mysql: 支持索引,通过虚拟列的功能可以对JSON中部分的数据进行索引。(比PG和MongoDB弱一些,通过json_extract()函数做一些简单查询)
- PostgreSQL: 支持检索,可以复杂查询
- MongoDB: 支持检索,可以复杂查询(支持map reduce)
ORM框架对Json类型的支持:
- sqlAlchemy支持postgresql数据库的对json和jsonb格式字段映射,并支持针对json和jsonb格式的查询。查看orm示例
使用sqlalchemy对jsonb格式的存储与检索
- 定义model模型
1 | from sqlalchemy import Column, Integer, String, cast |
2. 增加对象
1 | if __name__ == '__main__': |
3. 查看数据库存储
id | name | data |
---|---|---|
1 | xiaohong | {“value1”: “foo1”} |
4. 对自定义字段进行检索
1 | query_obj = session.query(MyDataClass1).filter( |
MongoDB存储自定义字段
前面三种都是基于关系型数据库实现自定义存储方式,而利用mongodb天然支持对json格式的存储特性也可以实现自定义字段的存储。
优点
- 支持对json格式的存储
- 不需要提前建表,存储简单
- 易扩展,大数据量的高可用性
缺点
- 复杂对象的存储查询困难
- 事务方面处理不足
- 不适用于关系性强、业务逻辑复杂的系统
- 系统开发成本加大