抢购商品前准备工作
商品表、订单表(订单号设置唯一键)、账单表、支付回调表
秒杀/抢购商品表字段:
商品ID
开始时间
秒杀/抢购时间(例如1个小时的抢购时间)
库存(秒杀/抢购)数量(100 件)
限购数量(每人购买1件)
订单超时(订单创建多长时间未支付,系统自动取消订单,30分钟)
缓存表
秒杀/抢购商品表:redis hash 表(redis_good,key=商品ID , value= 商品信息,可以选择其他数据类型,具体根据自己的业务需要)
商品库存表:redis key 表(redis_good_stock,key=商品ID, value=库存数量 )
商品订单表:redis list 表(redis_order,key=good_order,value=商品订单号)
用户购买商品数量表: redis key 表(redis_good_user,key=商品ID_用户ID,value=购买商品的数量)
订单超时记录表: redis key 表(redis_good_order_overtime,key=商品ID_用户ID,value=1,过期时间30分钟)
1、将秒杀/抢购商品表数据取出存入redis_good
2、商品库存 foreach 存入redis_good_stock
3、商品详情页,后端查询出数据,存入缓存,返回前端;前端接受数据缓存页面,如果用户客户端刷新缓存,重新请求后端缓存,如果后端缓存不存在,重新查询数据,并写入缓存。
创建商品订单
1、判断商品(redis_good )是否达到抢购时间,如果没有到达禁止购买或原价购买
2、如果已经到达抢购时间,判断商品库存数量(redis_good_stock)。
3、判断用户是否超出限购数量
① 用户是否抢购过(redis_good_user),加上当前的是否超出限购数量,如果超出禁止购买或超出限购数量商品原价购买。
② 当前用户选择商品数量(redis_good_stock),如果超出禁止购买或超出限购数量商品原价购买。
4、用户创建订单
① 商品 redis_good_stock 表执行 -1 操作,如果 -1 小于0 ,返回前端库存不足
② 如果库存(redis_good_stock)操作 -1 大于等于 0 ,创建商品订单号存入redis_order,进入订单业务队列(如果订单号存入redis_order 表失败,redis_good_stock 执行 +1 操作),返回前端端商品订单号;
队列传入数据:当前商品信息(redis_good )、商品订单号、用户ID、购买数量、时间
③ 记录订单下单时间(redis_good_order_overtime),判断是否超时
5、业务处理放入 think-queue 队列(也可以选择其他队列)中
开启事务,写入mysql 订单表数据,商品库存 -1 ,删除 redis_order 表中的订单号,如果操作失败,返回前端订单处理失败(或在队列中以消息推送的方式通知前端订单处理失败);
如果操作成功, 记录用户购买商品数量(redis_good_user)
订单列表页(订单详情页)
判断用户是否超时未支付(redis_good_order_overtime),如果超时用户购买商品数量(redis_good_user )- 订单中的购买的数量,商品库存(redis_good_stock)中 + 订单中的购买的数量
用户支付
判断数据库中是否存在当前订单数据
① 如果有数据,用户提交支付进入支付队列中执行,开启事务,第三方支付回调写入 pay_notify(商品ID,订单号,回调第三方,时间)支付回调表
② 如果没有数据,用户提交了支付,开启事务,先执行订单业务【写入mysql 订单表数据,商品库存 -1, 记录用户购买商品数量(redis_good_user)】 再执行支付业务。
注意:写入mysql 订单表使用 try{}cache(){},防止与订单队列业务(订单号唯一键)冲突,如果订单列队在次执行当前订单业务必然失败,同时删除了 redis_order 表中的订单号,所有此处不需要额外删除 redis_order 表中的订单号。