后端存储实战课
李玥
美团高级技术专家
44005 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 30 讲
结束语 (1讲)
后端存储实战课
15
15
1.0x
00:00/00:00
登录|注册

01 | 创建和更新订单时,如何保证数据准确无误?

更新数据同时自增版本号
每次更新数据前校验版本号
利用数据库的主键唯一约束
生成订单号的服务
版本号机制
让订单服务具备幂等性
查询订单,包括用订单数据生成各种报表
随着购物流程更新订单状态
创建订单
如何解决ABA问题?
如何避免重复下单?
订单系统的核心功能和数据
创建和更新订单时,如何保证数据准确无误?

该思维导图由 AI 生成,仅供参考

你好,我是李玥。
订单系统是整个电商系统中最重要的一个子系统,订单数据也就是电商企业最重要的数据资产。今天这节课,我来和你说一下,在设计和实现一个订单系统的存储过程中,有哪些问题是要特别考虑的。
一个合格的订单系统,最基本的要求是什么?数据不能错。
一个购物流程,从下单开始、支付、发货,直到收货,这么长的一个流程中,每一个环节,都少不了更新订单数据,每一次更新操作又需要同时更新好几张表。这些操作可能被随机分布到很多台服务器上执行,服务器有可能故障,网络有可能出问题。
在这么复杂的情况下,保证订单数据一笔都不能错,是不是很难?实际上,只要掌握了方法,其实并不难。
首先,你的代码必须是正确没 Bug 的,如果说是因为代码 Bug 导致的数据错误,那谁也救不了你。
然后,你要会正确地使用数据库的事务。比如,你在创建订单的时候,同时要在订单表和订单商品表中插入数据,那这些插入数据的 INSERT 必须在一个数据库事务中执行,数据库的事务可以确保:执行这些 INSERT 语句,要么一起都成功,要么一起都失败。
我相信这些“基本操作”对于你来说,应该不是问题。
但是,还有一些情况下会引起数据错误,我们一起来看一下。不过在此之前,我们要明白,对于一个订单系统而言,它的核心功能和数据结构是怎样的。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

订单系统在电商系统中扮演着重要角色,因此订单数据的准确性和完整性至关重要。为了确保数据的准确性,开发人员需要编写正确且无Bug的代码,并正确使用数据库的事务机制来确保数据操作的原子性。订单系统的核心功能包括创建订单、更新订单状态以及查询订单等,对应的数据库表包括订单主表、订单商品表、订单支付表和订单优惠表。为了实现订单服务的幂等性,可以通过为订单系统增加“生成订单号”的服务,并在用户提交订单时带上这个订单号作为主键,从而利用数据库的唯一约束特性来保证订单创建的幂等性。在处理更新订单服务时,特别需要注意ABA问题,可以通过引入版本号机制来解决。通过这样两种幂等的实现方法,可以保证订单表中的数据都是正确的。文章提供了解决ABA问题的通用方法,以及对实现服务幂等性的思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端存储实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(89)

  • 最新
  • 精选
  • 李玥
    置顶
    hello,我是李玥。之后我都会在留言板上同步上节课思考题的答案,欢迎你跟我一起学习讨论。 在课前加餐这节课里,我给你留了道思考题,让你作为公司的CTO,想一想上节课我们提到的电商系统,它的技术选型应该是什么样的? 关于这个问题,我是这么理解的。 技术选型本身没有好与坏,更多的是选择“合适”的技术。对于编程语言和技术栈的选择,我认为需要从两方面考虑,一方面就是团队的人员配置,尽量选择大家熟悉的技术,第二个方面就是要考察选择的技术它的生态是不是够完善。这两个原则在选择编程语言、技术栈、云服务和存储的时候都是适用的。 如何根据业务来选择合适的存储系统,这是个很大的话题,我会在后面的课程中陆续穿插的来和你讲,什么场景下应该选择什么样的存储,敬请期待。
    2020-02-26
    6
    64
  • 川杰
    请问,生成订单号 服务的一般逻辑会是怎样的?思来想去,如果要想这个ID全局唯一,只能带上时间,可是如果带上时间,像那种,不小心点了两次按钮的情况,必然是两个不同的订单号;请问这个问题怎么解决?

    作者回复: 如果单纯是生成GUID(全局唯一ID)方法有很多,比如小规模系统完全可以用MySQL的Sequence或者Redis来生成。大规模系统也可以采用类似雪花算法之类的方式分布式生成GUID。 但是订单号这个东西又有点儿特殊要求,比如在订单号中最好包含一些品类、时间等信息,便于业务处理,再比如,订单号它不能是一个单纯自增的ID,否则别人很容易根据订单号计算出你大致的销量,所以订单号的生产算法在保证不重复的前提下,一般都会加入很多业务规则在里面,这个每家都不一样,算是商业秘密吧。

    2020-02-26
    20
    65
  • 业余爱好者
    每次请求之前必须先生成一个唯一的请求id,服务端将该id暂时放入redis。客户端请求时必须携带上这个id,借口会首先到redis中查询,如何有的话就继续后续的处理逻辑,同时删除该id,灭有的话就退出,返回不能重复请求的错误到客户端。 一句话总结:每次处理必须对应一个一次性的token。

    作者回复: 这个思路非常好,并且可以适用很多的场景。 如果是超大规模的系统,可能用一个Redis实例来生成和验证这个GUID就忙不过来了,大家也可以想一下有没有什么性能上更好的方式?

    2020-02-26
    26
    56
  • 家庆
    李老师好,请问生成一个唯一订单号放在前端,如何保证客户绕过客户端直接发送请求恶意乱填订单号的问题,符合规则的订单号,而这个订单号有可能是后续系统生成的。

    作者回复: 有的同学已经在留言区给出了答案,那就是,在Redis里面缓存一下给出去的订单号,收到客户端请求的时候,先验证一下这个订单号在缓存中是否存在,就可以解决这个问题了。

    2020-03-06
    5
    33
  • 鸠摩智
    老师,生成全局唯一订单号如果不是自增的,插入mysql innodb表的时候,底层的B+树索引是不是会发生页分裂等问题,影响插入性能?如果遇到大促,短时间生成大量订单,写入会成为瓶颈不?

    作者回复: 这确实是一个需要考虑的性能问题。 所以很多业务在设计订单号规则的时候都不是完全随机的,一般都是递增的。这种情况下,页分裂就不会特别严重。

    2020-02-28
    14
    29
  • Sunday
    老师,用户手机号注册会出现多次注册现象,但因为有注销功能,我又不能设置成唯一主键,所以想问下有没有什么好的解决办法?目前是用redis锁控制并发的。还有ABA问题,一般业务中这种更新都是牵扯到更新多条,使用事务,但事务的话因为隔离级别问题,比如可重复读,感觉并发情况还是有问题

    作者回复: 手机号注册重复这种情况,可以简单的用insert if not exist来解决,比如: insert into user (name, phone) select * from (select '张三', 13988888888) as tmp where not exists ( select phone from user where phone = 13988888888 ) limit 1;

    2020-03-07
    13
    21
  • 王超
    老师,如果是一个预约中台的项目,只对外提供API能力,前端的预约入口应用不由自己负责,无法要求别人的前端应用在进入下单界面的时候就调用统一生成单号的服务,这种情况下有什么推荐方案么,感谢

    作者回复: 这种下单接口,订单内容中一般都会有用户ID,可以通过“1秒钟内每个用户只允许最多下1单”,这种方式来判重。因为一般来说,由于重试导致的重复请求之间的时间间隔都是比较短的。 INSERT INTO my_orders (...) SELECT * FROM (SELECT 'aaa', 'bbb', 'ccc') AS tmp -- 实际要insert的数据 WHERE NOT EXISTS ( SELECT userid FROM my_orders WHERE userid = 'bbb' and last_update_time > now - 1秒 ) LIMIT 1;

    2020-03-24
    2
    18
  • 约书亚
    请教您一个实际问题: 无论采用哪种生成订单id的方式,短时间内都可能出现靠前的id后提交(生成订单的问题),这样一定程度上数据库接收到的id不是严格按时间递增的。而页面浏览的场景,尤甚。 请问在您做过的系统里,这会带来一定程度上的性能下降嘛?

    作者回复: 你是指在数据库中插入数据的时候,写入索引的性能下降吗?

    2020-02-27
    23
    18
  • fgdgtz
    老师你好,我觉的订单号设为唯一索引约束即可,仍然有个自增主键,订单号对外用,主键不暴露,这样表空间还是连续紧密的,其他关联订单表仍然以订单号作外键

    作者回复: 这样也是没问题的,很多情况下架构不是只有一种解决方案的。这种设计的好处就是主键连续,使用订单号做主键的好处是,最常用的按订单号查询会少走一次索引,各有优劣,都可以选择。

    2020-03-21
    8
    16
  • leo
    关于数据报表类数据,现在主流解决方案能否推荐一下。本来想推es,但运营人员觉得操作复杂。大厂的实践是什么呢

    作者回复: 后面我会专门讲,海量数据应该怎么查才会快一些。 但是,有一个原则上,底层用什么存储,应该尽量对最终用户透明,不要因为换了存储系统,就改变用户的操作习惯。

    2020-03-22
    2
    10
收起评论
显示
设置
留言
89
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部