这几天设计讨论的一点心得
这几天和同事讨论新项目、系统的设计方案。理越辩越明,有一些以前模模糊糊的想法、概念,都随着讨论,有时甚至是争论而变得清晰明确。
服务接口的幂等性。
以前做服务接口,都没考虑过这个问题。这次静下来想了想,觉得服务接口必须具备幂等性才对。
幂等性就是说,在没有其它操作的情况下,对同一个服务接口无论调用多少次,系统状态以及返回结果都应当是一样的。
如果不是这样,前后脚两个操作,一个告诉我说OK了,另一个告诉我说出异常了。这算什么鬼=。=
就一般的增删改查来说,删改查基本上是很容易支持幂等性,甚至天生幂等的。
但是新增,由于语义上每次都要追加一条数据,那么多次操作当然会多次增加数据咯。
让新增操作变成幂等性操作,需要有重复校验。页面提交上可以带token,但是服务接口呢?
恐怕只好做唯一数据校验吧……这个校验又可能涉及到事务和并发的处理……
于是麻烦了,算了,直接抛出异常告诉服务调用者“数据重复”吧!
这是服务还是别的什么鬼=。=
我这次做的一个接口,向着“幂等的新增接口”走了一步,保持其对外的语义是:你给我一笔数据,我返回一个唯一标识;相同的数据,返回相同的标识。
自我感觉良好o( ̄▽ ̄)ゞ
数据库字段设计
在与同事讨论系统中一个数据库设计时,谈到了一个数据库字段设计的选择思路:
数据库是严格遵循范式以获得sql的各种便利,还是存复杂结构(数组,甚至json)以获取更强的灵活性和扩展性?
设计场景
系统需要为实体A、实体B和B1做相关配置。其中:
- A:B是1:n的配置关系
- A:B1是1:1的配置关系
- B和B1是同类型的数据
未来,可能出现:
- A:D配置
- A:E配置 ……
争论的焦点
主要是以下两种方案。
遵循范式的方案
表字段设计为“商户id”、“银行通道id”这两个字段,每一条商户-银行通道的配置存一行,例如(示例;其它关联表或基础配置表没有写出来):
A | B |
---|---|
123 | B1 |
123 | B2 |
123 | B3 |
456 | B2 |
456 | B4 |
存复杂数据结构的方案
表字段设计仍然是两个字段,但每一条数据中的“银行通道id”字段,存数组(甚至讨论过存json字符串的方案),例如:
A | B |
---|---|
123 | B1,B2,B3 |
456 | B2,B3 |
789 | {"C":"B1","B":B3","B5"} |
两种方案的优缺点
遵循范式的方案可以最大程度的支持sql。例如,如果运营需要统计有多少A配置了指定的B(这是我在做另一个类似的需求时实际遇到过的,算是前车之鉴),则这种方案可以很便捷的得到结果。
但是,为了遵循范式,数据量(行数,并非实际的存储空间)会变得很大。最糟糕的情况下,可能出现50w「A的数量」*(19「B的数量」+1「C的数量」)=1千万行数据。从这样大的数据量中查出20行数据(而且还要进行关联查询),查询效率堪忧。
另外,遵循范式使得库表设计严格的规定的数据结构及实体间关系。也就是说,这个表只支持A到B/C的映射配置。如果后续需求中的D或者E不是以这种结构、关系进行配置的,那么就只能用新的表结构来扩展了。
存复杂数据结构的方案的优缺点基本上恰好相反。它对sql的支持比较差,数据需要在代码中进行额外的处理。尽管实际占用的存储空间可能会更大一些,但是数据行数会大量减少(使用json的话,最糟糕情况就是50w行),查询效率会好一些。而且,只要数据不超长,json可以兼容各种各样的数据结构,非常的灵 活便捷。
我们的讨论结果
合天弘运文武睿哲恭俭宽裕孝敬诚信功德大成仁
之交哥二话没说,使用了遵循范式的方案。
我的理解是这样
- 有前车之鉴,B的配置数据可能要用作sql中的where字句条件。如果用复杂数据结构,这一点很难支持。
- 数据行数的隐患可以配合另一种设计方案解决。
- 新的数据结构可以通过扩展新的表来实现。
这样一来,复杂数据结构的优势缩小,而劣势就被放大了。
©著作权归作者所有:来自51CTO博客作者winters1224的原创作品,请联系作者获取转载授权,否则将追究法律责任 这几天设计讨论的一点心得 https://blog.51cto.com/winters1224/1613832