• 程序员过关斩将--你的业务是可变的吗(福利你领了吗)


    温馨提示

    周末菜菜送的书,你领了吗?没领的话,关注公众号之后参加活动哦!

    菜菜哥,我又让领导骂了

    来,哥安慰一下你,说说你挨骂的原因,让哥乐一乐

    ....是这样的,我做的商城有一个订单统计的功能,我除了记录订单之外,还记录了下单人的信息,其中有省市区县id的信息

    倾听中.......

    然后业务部门会有根据区域(省市区县)订单的各种统计需求,比如xx省的订单数,订单总金额等统计。

    倾听中...

    由于人员的区域信息可能会变动,用户区域信息就算是同步或者不同步都会出现差错

    每个用户信息只存在一条记录?

    是的。比如用户A现在属于省id为1000的省,生成了一个订单,这个省的订单数统计会加1,假如订单总数变为了20001,然后用户A所属的省的Id变为了1001,那Id是1000的省的订单总数又变成了20000

    我明白你的问题了,来,妹子,哥给你好好说说这个事

    请不要跟我说用ES或者其他,其实很多中小公司的业务就是如此,就是基于mysql或者sqlserver 来搞这样的业务

    业务场景


            不知道通过D妹子的阐述,大家了解情况了没。这里菜菜再详细说一下。D妹子的程序记录了订单的log来供其他业务(比如统计)使用,这里就以统计业务来说,OrderLog表设计如下:


    列名数据类型描述
    OrderId nvarchar(100) 订单号,主键
    UserId int 下单用户id
    Amount int 订单的金额
    其他字段省略...


    除此之外还有一个用户信息表UserInfo,设计如下:

    列名数据类型描述
    UserId int 用户id,主键
    ProvinceId int 用户省的id
    CityId int 用户市的id
    CountyId int 用户区县的id

    涉及到拆单等复杂的订单操作,表的设计可能并非如此,但是不影响菜菜要说的事

    变数的业务


    现在假如要统计某个省的订单总数,sql如下:


    select count(0from OrderLog o inner join UserInfo u on o.UserId=u.UserId where ProvinceId=@ProvinceId


            有问题吗,sql没问题,这时候用户A的省市区县信息突然变了(也许是在其他地区买房,户口迁移了),也就是说UserInfo表里的信息变了,那用以上的sql统计用户A以前省市区县的订单信息是不是就会出错了呢?(产品狗说在哪下的订单就属于哪的订单)

    业务的定位


            以上的问题你觉得是不是很简单呢?只要稍微修改一下表也许就够了。但是,菜菜要说的不是针对这一个业务场景,而是所有的业务场景的设计。那你有没有想过为什么D妹子的设计会出现这样的问题呢?

            深刻理解业务才能避免以上类似的错误发生,一定要深刻理解不变和可变的业务点。 拿D妹子的统计来说,你的业务是统计区域的订单数,这个业务在产品设计上定义的是不变性,也就是说在行为产生的那个时间点就确定了业务性质,这个业务的性质不会随着其他变而变。具体到当前业务就是:用户在X省下的订单不会随着用户区域信息的变化而变化,说白了就是说用户在X省生成的订单永远属于X省。

            谈到业务性质的不变性,对应的就有业务的可变性。假如你开发过类似于QQ空间这样的业务,那肯定也做过类似访客的功能。当要显示访客记录的时候,访客的名称在多数情况的设计中属于可变性的业务。什么意思呢?也就是说一个用户修改了姓名,那所有显示这个用户访问记录的的地方姓名都会同时改变。

            说到这里,各位再回头看一下D妹子的业务,这里又牵扯到一个系统设计的问题,众所周知,一个好的系统设计需要把业务的变化点抽象提取出来,D妹子订单统计的业务变化点在于用户的省市区县会变化,订单的金额、订单号等信息不会变化。所以你们觉得是不是D妹子的数据表可以修改一下呢?


    数据表的改进

    01

    改进用户信息

    按照以上的阐述,D妹子业务的变化点在于用户的省市区域信息,所以可以把用户信息的表抽象提取出来,主键不再是用户id


    列名数据类型描述
    Id int 主键Id,主键
    UserId int 用户id
    ProvinceId int 用户省的id
    CityId int 用户市的id
    CountyId int 用户区县的id


    这样的话用户订单log表中就变为

    列名数据类型描述
    OrderId nvarchar(100) 订单号,主键
    UserBId int 对应用户表中的主键id
    Amount int 订单的金额
    其他字段省略...


    这样设计的话,如果用户的省市区县信息有变动,相应的用户信息表中会存在多条用户省市区县数据

    这里的用户信息表并非是用户对象的主表,而是根据订单业务衍生出来的表

    02

    改进业务数据表

    根据业务的变性和不变性,既然把订单区域统计的业务定义为不变的业务性质,那订单的log表完全可以这样设计

    列名数据类型描述
    OrderId nvarchar(100) 订单号,主键
    UserId int 下单用户id
    ProvinceId int 用户省的id
    CityId int 用户市的id
    CountyId int 用户区县的id
    Amount int 订单的金额
    其他字段省略...


    写在最后

    各位读到这里,可能会感觉菜菜这次写的其实很鸡肋,但是,D妹子的场景却是真实环境中遇到的问题。问题的本质还是变性业务和非变性业务的定义和划分,和架构设计一样,数据库的设计其实也需要把变动的业务存储点进行抽象,其实应该说是抽离出来。


    希望大家有所收获 --菜菜

    互联网之路,菜菜与君一同成长

    长按识别二维码关注

    你点的每个推荐,我都认真当成了喜欢
  • 相关阅读:
    深入解析Hibernate核心接口
    Hibernate基本原理
    深入hibernate的三种状态
    Hibernate commit() 和flush() 的区别
    Hibernate中的merge使用详情解说
    Record is locked by another user
    Vue路由router-link的使用
    Vue-router的基本使用
    Vue把父组件的方法传递给子组件调用(评论列表例子)
    Vue中子组件调用父组件的方法
  • 原文地址:https://www.cnblogs.com/zhanlang/p/10626528.html
Copyright © 2020-2023  润新知