前言
购物车作为整个电商系统中核心的业务逻辑,本文对于其中的一些操作细节处理做了详细的梳理(仅代表本人遇到的业务场景),对于特殊场景的细节处理在文章末尾做了讲解。
文章中商品默认为电子商品,不考虑库存
购物车
查询购物车
- 获取购物车缓存数据
- 判断是否需要更新购物车
- 每人购物车都配备一个时间字段
- 系统商品存在一个最后操作时间标识
- 比较时间确认是否为最新版商品信息
- 校验所有商品的状态
- 上下架、权限、版权
- 判断价格,使用加密价格进行校验
- 更新缓存并返回数据
加入购物车
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 获取购物车数据(redis hash存储商品信息)
- 校验并更新
- 获取分布式事务锁
- 是否超过购物车商品种类数量上限
- 是否存在于购物车、已购买过
- 商品正确性(是否存在、版权、上下架、阅读权限)
- 使用最新商品数据更新购物车、并更新标识
- 释放锁
- 返回数据
批量添加到购物车
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 校验商品列表有无重复
- 获取购物车数据(redis hash存储商品信息)
- 校验并更新
- 获取分布式事务锁
- 是否超过购物车商品种类数量上限
- 分批次校验商品是否已经购买
- 过滤出未添加的商品进行添加
- 商品正确性(是否存在、版权、上下架、阅读权限)
- 使用最新商品数据更新购物车
- 释放锁
- 返回数据
结算
去结算
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 购物车过滤出待确认的商品,并校验商品数量是否来自于购物车
- 计算价格
- 优惠、运费等
- 返回数据
- 商品信息
- 总价
- 令牌,用于提交订单使用
直接购买去结算
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 分批次查询商品,校验商品正确性
- 计算价格
- 优惠、运费等
- 返回数据
- 商品信息
- 总价
- 令牌,用于提交订单使用
订单
提交订单
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 防重令牌来自于去结算或直接购买
- 校验用户权限是否支持此次购买
- 校验发票等信息填写
- 校验商品是否已经购买过
- 创建订单
- 获取分布式锁
- 获取最新商品数据,验证商品正确性(是否存在、版权、上下架、阅读权限)
- 计算价格,校验价格是否变动
- 构建订单数据、订单商品数据
- 保存订单相关数据,发送订单信息到延时队列
- 释放锁
- 返回提交订单的令牌,并存入缓存,过期时间与订单一致
直接购买
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 防重令牌来自于去结算或直接购买
- 校验用户权限是否支持此次购买
- 校验发票等信息填写
- 校验商品是否已经购买过
- 获取最新商品数据,验证商品正确性(是否存在、版权、上下架、阅读权限)
- 计算价格
- 创建订单
- 获取分布式锁
- 保存订单相关数据,发送订单信息到延时队列
- 释放锁
- 返回提交订单的令牌,并存入缓存,过期时间与订单一致
购买会员
- sm2加密传参、校验参数
- 校验防重令牌,防止重复提交
- 查询会员信息,创建订单
- 保存订单相关数据,发送订单信息到延时队列
取消订单
- sm2加密传参、校验参数
- 获取分布式锁(与支付相同)
- 判断
- 预支付缓存
- 支付缓存
- 根据状态取消/支付订单
FAQ
如何保证数据更新后购物车同步更新
某商品可能存在众多购物车中,商品一旦发生修改,就涉及缓存的更新,大量缓存更新是不可取的。这里借鉴了Redis生成RDB快照时的思路,当用户查询购物车时,判断是否更新购物车。
ps:如何进行判断操作,当修改商品信息后,记录此修改的时间,购物车中同样存储此时间,若两个时间不一致说明商品有修改,需要更新购物车。
购物车商品有效性校验
购物车数据存储在缓存中,正常情况下商品不更新不需要更新购物车,但是有部分数据需要每次验证,例如商品版权信息,带有时效性的信息,这部分时间数据存储在缓存中,在每次查询时需要在内存中进行逻辑判断。
购物车存储数据内容有哪些
方案有两种
- 只存储商品id等信息,查询时进行关联
- 存储商品全部信息,查询时判断是否最新
根据两种方案选择合适的即可。
去结算&提交订单区别
去结算:对购物车中选择待购买的商品,后台计算价格、优惠、校验等一系列操作后返回给前端展示。
提交订单:在去结算展示页面添加收货地址等信息后,后台创建订单的操作。
购物车购买和直接购买区别
购物车购买:购物车是缓存数据,需要对数据进行校验正确性。
直接购买:不需要经过购物车,直接查询最新数据进行计算价格购买。
还有一点是,在多端情况下,购物车购买需要添加分布式锁,而直接购买只需要创建订单时添加。
为什么使用分布式锁
在考虑多端情况下,用户在PC和APP同时对商品进行下单,可能存在校验是否购买过、库存数相关内容时校验显示通过,实际不通过的情况。为了避免多端带来的问题,添加了分布式锁。
如何验证订单是否过期
订单创建完成后,会加入到延时队列,在延时队列消费订单前,订单可能进行支付也可能搁置,等到了到期时间后,延迟队列首先对支付源(微信、支付宝)进行关单处理,防止用户支付,关单成功后对订单的状态进行修改即可。
极端情况,用户扫码进行支付途中订单到期,有两种情况:
- 关单成功,用户扫码支付提示失败。
- 关单失败,说明用户已支付,需要走成功逻辑。
在关单前查询支付状态,根据状态关单即可。
预支付缓存和支付缓存关系
预支付:缓存时间与订单超时取消时间一致,30min,只存储订单号
支付缓存:每种支付方式只有5分钟时间,存储支付方式相关信息
若预支付缓存不存在,说明订单已超期,无法支付。
支付缓存存在说明曾调起过支付,还未关闭(调起的支付有效时间与此缓存一致)。
ps:在支付篇中重点讲解
防重令牌获取
顾名思义防止重复提交,但是其中也有顺序,例如订单中的令牌都是从结算接口返回的。
购物车、结算的令牌时从接口获取的。
支付可以从订单返回数据中获取,也可以单独请求接口获取