引言
当我们开始一个新的业务应用设计开发呢,无论是前台应用还是中后台应用,在前后端分离的团队组织划分及协作时,前台应用专注于交互体验的提升,涉及到多端(PC,H5,iOS,Android,小程序 - 支付宝,淘宝,微信...),大量的创新在于如何同一个页面开发复用提效统一输出到各端,定义DSL,结合可视化搭建,no code/low code进行页面开发;同时应对各端所需求数据的不同,GraphQL的诞生让客户端可以从服务端 ask for what you need, get exactly that。中后台应用可应用可视化搭建体系,快速开发前端应用。它们都需要服务端提供API。React/Vue/Angular应用构建网络上,内网的模板或代码可以借鉴快速创建应用代码结构;SpringBoot/PandoraBoot的模板也能快速搭建出服务端代码结构。服务端的SOA/微服务,docker部署,k8s,分布式应用系统架构,前端的微前端应用架构在网上有大量的代码与文章可以学习,基本上能够采用一些最佳实践开始前端与服务端的应用开发;那底下的数据库是如何设计呢?关系型数据库,分库分表,NoSQL也有大量的资料可以学习,而且也有成熟的方案参考。But,数据库的实体模型应该如何设计呢?我们在系统设计时,花在数据库的实体模型上的精力又有多少呢?撇开工作中积累的经验,网络上很少有资料展示真实的CRM,Ecommerce,HRMS,ERP的数据实体设计。是不是每次开发一个新的应用系统,应用代码可以利用模板快速搭建,但数据库模型的设计基本是从0开始,没有太多积累可用(自身的经验除外)。可是客户关系管理,产品管理,订单处理,人力资源管理,财务管理从上世纪70年代以来在当下仍是以公司为主要组织方式的情形下业务概念上有翻天覆地的变化吗? 这五六十年的系统数据模型(Data Model)依赖于架构师或数据建模师自身的经验进行迭代设计,知识经验仅限于小圈子中传播,且容易遗失。
这一系列文章基于 Len Silverston 教授的 A Library of Universal Data Models for All Enterprises(1999年第一版,2001修订版)三册书,结合实际的系统设计对企业级数据模型设计进行分享,除了介绍一些已有数据模型外,更重要的是一些数据模型设计的范式介绍。
免责声明:文中所有示例非阿里真实系统
基础实体
枚举
我们在应用中常要用到枚举类型,如产品类型:普通云产品、软件、服务、软硬一体、解决方案等,订单类型有:新购,续费,升级,降级,扩容等等,这些类型一般会有不同的业务逻辑处理,就系统而言属于meta data。下面有两张表,可将所有的枚举类型用一张表来存储。
而且Enumeration
还可以通过parentEnumId
来描述 Subtypes 与 SuperTypes,如下图所示
Organization (Supertype)
|-- Legal Organization (Subtype and Supertype)
| |-- Corporation (Subtype)
| |-- Government Agency ((Subtype)
|-- Informal Organization (Subtype and Supertype)
|-- Team (Subtype)
|-- Family (Subtype)
|-- Other Informal Organization (Subtype)
状态
这是一个经典的状态工作流设计数据模型,Atlassian JIRA应该也是这样的数据模型。
我们可定义
statusItem: open, inProgress, resolved
statusFlow:
'default': 严格限定只能open->inProgress->resolved,那么这里两个状态间流转(transition)的箭头
就是两个statusFlowTransition
'unrestricted': 也可以很松散的定义状态流转,open->inProgress, open->resolved,
inProgress->resolved, inProgress->open, resolved->inPorgress, resolved->open
六个statusFlowTransition
我们可以动态的更改绑定issue的工作流(如果状态兼容,状态不兼容时可做类似JIRA的迁移工具),如例子所示,该issue可在default
与unrestricted
两个工作流中任意切换。这里的issue可以延伸至任意需要工作流管理的entity,如产品编辑发布,网站内容编辑审核发布,订单状态处理等。
Uom (Unit of Messurement)
中文在描述数量时实际是由数词与量词构成。数词有一、二 、三、四、五、六、七、八、九、 十、百、千、万、亿等;量词有头、匹、条、斤、公斤、斗、升、尺、寸、丈。数词对应英文中的quantity,量词里的度量衡对应英文unit of measurement。度量衡之间可以互相转换,如一丈等于三尺,一尺等于三寸。
UomConversion
在转换时conversionFactor
先乘,然后加上conversionOffset
;当反向转换时那就先减conversionOffset
,然后再除以conversionFactor
比如
uomConversionId | uomId | toUomId | conversionFactor | conversionOffset |
---|---|---|---|---|
DATA-SIZE-GM-MB | Gigabyte [DATA_GB] | Megabyte [DATA_MB] | 1000 | |
AREA-cm2-in2 | Square Centimeter [AREA_cm2] | Square Inch [AREA_in2] | 0.155 | |
TEMP-C-K | Degrees Celsius [TEMP_C] | Kelvin [TEMP_K] | 1 | 273.15 |
这里出现了第一个数据模型设计范式,在UomConversion
中有fromDate
与thruDate
字段,它俩用来表示有效期,thruDate
为null
表示永久,判断有效期的表达式为 fromDate < nowTimestamp(or compareTimestamp) <= thruDate
。
比如美元与人民币的汇率可以设置每天一个汇率
uomConversionId | uomId | toUomId | fromDate | thruDate | conversionFactor | conversionOffset |
---|---|---|---|---|---|---|
USD-CNY-2019-07-29 | USD | CNY | 2019-07-29 00:00:00 +0800 | 2019-07-30 00:00:00 +0800 | 6.8794 | |
USD-CNY-2019-07-28 | USD | CNY | 2019-07-28 00:00:00 +0800 | 2019-07-29 00:00:00 +0800 | 6.8589 | |
USD-CNY-2019-07-27 | USD | CNY | 2019-07-27 00:00:00 +0800 | 2019-07-28 00:00:00 +0800 | 6.8589 |
Geography (Geo)
ISO 3166 (https://www.iso.org/iso-3166-country-codes.html) 定义了各个国家代码,另外可参考
- http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
- http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
- http://en.wikipedia.org/wiki/ISO_3166-1_numeric
Geo
中type
可为
- Country
- Province
- State
- City
- County
- ...
GeoAssoc
中type
可为
- Region of a Larger Geo
- Geo Group Member
- Administrative City
通过Region of a Larger Geo
关联关系可以构建出国家-省-市-县,国家-州-县-市的行政区树。
Geo坐标可定义GeoPoint
实体,这在后面人与组织的介绍时再提及。
Audit Log
这里面pkSecondaryValue
与pkRestCombinedValue
是用于有多个主键字段情况,如果只是一个主键值,使用pkPrimaryValue
即可。它可记录某个entity/表(changedEntityName
)的某个字段(changedFieldName
)的变化oldValueText
->newValueText
,同时记录下修改人与修改时间。
最典型的应用就是JIRA或Aone的修订记录
安全
用户账号与权限
用户账号是用于用户登录应用系统的账号,它记录着与登录相关的信息,常见的误区是用用户账号来表达人/会员,人/会员可用后面的人与组织的参与人来表达。
-
resetPassword
:一个随机密码,仅能用于更新密码 -
passwordBase64
:为Y
表示currentPassword
是Base64编码,否则是Hex编码 -
publicKey
:使用key验证时的RSA public key -
hasLoggedOut
:当用户登出时设为Y,登入时设为N
UserPermission
定义权限点,类似于ACL,权限通过UserGroup作用于UserAccount。