另外,可能还有一些增强型需求,让客户体验更好,比如用户可以创建订单之后付款之前,将订单取消,或者由系统跑批将用户长时间未支付的订单关闭,这会产生一种新的action——‘close关闭’,对应的会产生一种新的有意义的BizState——‘订单关闭/取消’,这个不属于核心流程中的,且并无纠结之处,不予详细讨论,罗列如下:
结论综上,我们可以得出放入数据库’订单状态‘字段的标准:核心业务流程,向前单向依赖。扩展到其他业务实体是一样的,这里说的’订单状态‘字段实际是指该业务实体对应的数据表的主业务状态字段。我们把结论扩展一下:
如果某个action属于业务实体对应的核心业务流程,且该action单向依赖于其前向的action,则需要将这个action产生的BizState放入到业务实体对应的数据库表的主状态字段中记录。
OrderState字段记录的BizState业务状态有10种,其中4种是终态,其余状态为中间态。这些状态的流转关系为:
问题二、订单表的‘订单状态’字段的字典值的表示形式?
先列出可选项:使用数字标识、使用多‘位’存储方式标识、使用具有明确业务含义的英文字符串标识;对可选项做逐一解释:
a、使用数字标识——使用一个数字标识一种状态,并未要求是sequence的;如‘等待买家付款’表示为‘0’;
b、使用多‘位’存储方式标识——将某种行为是否发生对应的状态对应到一个位上,比如‘是否付款’定义在第一位,‘是否发货’定义在第二位,‘是否收货’定义在第三位,‘是否评论’定义在第四位,则状态‘卖家已收货未评论’可以表示为:0111;而‘等待买家付款’则表示为‘0000’;当然这里的‘位’可能是二进制的也可能是N进制,后面我们详细讨论。
c、使用具有明确业务含义的英文字符串标识——该方案和方案a类似,不过字典值变为具有明确业务含义的英文支付串,如‘等待买家付款’表示为‘WAIT_BUYER_PAY’;
方案a是数据库字段字典的惯用方式,简单直观,但是有一个坏处在于:当字典值较多时,数据库表的使用者记不住字典的含义,需要反复查找资料确认;有人会说将字典值写到字段的注释里,这个在实践中不是很靠谱,通常表建立后,如果字段增加了字典值,通常开发人员都会忽略更改字典值;而且在使用工具(如pl/sql)查询数据库时,并不会将所有字典值展示出来;
通过问题一的分析,可知:方案b使用多‘位’存储方式会增加复杂度,并没有必要,可以通过将‘是否评论’状态独立成一个字段进行表示。
方案c和方案a类似,好处在于通过字典值直接知道业务含义,坏处在于会给编码和手工查询时带来复杂度,通常人们也记不住‘等待买家付款’的英文字典是‘WAIT_BUYER_PAY’,那么手动写sql查询‘等待买家付款’时就犯迷糊了。
折中之后,我们组合方案a和方案c,得到方案d:另外建立一张字典表,存储:数字形式的字典值、字典英文名称、字典中文简称、字典解释;订单实体表的OrderState字段使用数字作为字典值。
对于方案d,看到OrderState的数字形式状态时,可以先看看字段注释是否有此字典的定义,如果没有就取查下字典表,得到字典值和含义;在编码和手动sql查询时也会变得比较容易,数字的位数毕竟要少些;建立字典表的其他好处还有:字典的解释可以写的很详细,在报表中要求展示字典中文名时,也能直接从数据库联表查询得到,而不必额外做一次映射。(有参考:数据库表设计(状态字段))
那么对于字典数量很少的状态字段是否有必要额外新建一张字典表呢?这个根据实际情况考虑,通常可以先不建,如果后续有业务场景需要再行创建也不迟。
而对于非业务实体表的系统日志/跑批记录表等的状态,则完全可以使用数字形式的字典,因为通常不会有业务场景使用到这些字典值,而且这些字典值域应当会比较小,所以没有必要为他们创建单独的字典表。
综上得出结论:
1、字典值域较多、变化较多、报表等业务场景会使用到的业务实体表的业务状态字段,使用‘方案d:新建字典表’的方案处理;如‘订单业务实体表’中的‘订单状态’字段。
2、字典值域较少、变化较少、报表等业务场景不会使用到的业务实体表的业务状态字段,使用‘方案a:使用数字标识字典’的方案处理;如‘支付宝的支付流水表’的‘支付流水状态’字段。
3、系统日志/跑批记录表的状态字段,使用‘方案a:使用数字标识字典’的方案处理;如‘待收货记录表’的‘跑批状态’字段。
问题三、数据库表的‘状态’字段使用何种类型列出可选项:number(N)、char(N)、varchar2(N),其中N是一个长度值。
这个问题主要需要考虑使用场景、扩展性、性能、存储。
‘状态’字段主要使用在查询场景,且通常是‘=’或者‘in’的查询,并没有区间类的查询,故三者差别不大;
对于性能,参考[原创]在Oracle 10g,Number、Char和Varchar2类型作为主键,查询效率分析 char(N)、varchar2(N)性能优于number(N),故舍弃number(N)。
考虑到扩展性,char(N)、varchar2(N)差不多;
考虑到存储,varchar2更加占用空间更小,故选择varchar2(N)。
综上:选择varchar2(N)作为数据库‘状态’字段的类型。
问题结论汇总1、订单表的‘订单状态’字段对应的字典值应当包含哪些状态值?对于‘已评论’、‘已退货’这类状态是放到‘订单状态’中?还是独立一个字段标识?
如果某个action(行为,如支付)属于业务实体对应的核心业务流程,且该action单向依赖于其前向的action,则需要将这个action产生的业务状态放入到业务实体对应的数据库表的主状态字段中记录。