1.什么是超卖现象?
2.如何解决超卖问题? 库存
解决超卖问题的关键是控制库存,使用Redisson中的AtomicLong[原子长整形]来初始化、减库存和增库存等操作。
1.商家前端请求维护菜品信息到
2.通过菜品服务将维护商品库存信息同步到DB(数据库中)
3.同步成功后将结果返回至菜品服务
4.构建商品的初始化库存并同步到Redis中(key是商品ID,value是商品个数)
5.在redis同步成功后将结果返回至菜品服务
6.在菜品服务中将菜品维护成功的结果返回至前端
atomic原子性,是因为atomiclong封装了自增和自减的操作
3.菜品的库存第二天如何更新?
通过Spring的bean生命周期理论,在项目启动时通过InitDish类初始化bean 读取数据库中的菜品库存,读取结束后同步更新到redis中
4.整个购物车操作的流程是什么?
添加购物车:
1.前端发送操作购物车请求,操作类型如果是add添加购物车
2.redis开始扣减库存,扣减成功返回true;扣减失败直接返回false,把错误信息返回给前端;
3.DB(mysql数据库)扣减库存,扣减成功返回true;扣减失败返回false,并且redis库存增加(增加数量是第二步扣减的数量);
4.判断该订单是否为首次添加,是创建购物车订单项;不是合并购物车订单项;
5.查询当前订单信息。
移除购物车:
1.前端发送操作购物车请求,操作类型如果remove是删除购物车
2.DB(mysql数据库)开始增加库存,增加成功返回true;增加失败直接返回false,把错误信息返回给前端并扣减增加的库存;
3.查询购物车订单项,判断该订单是否存在,存在判断购物车菜品数量;不存在,回滚菜品库存
4.判断购物车菜品数量是大于1还是等于1,如果大于1修改购物车订单项中的菜品数量;如果等于1,直接删除购物车订单项中的该菜品
5.查询当前订单信息。
6.将该菜品数量同步到购物车
5.购物车使用的是什么存储的? 你是怎么考虑的?-Redis 4个点
使用redis存储的。
1)redis是基于内存存储的,速度快,效率高;mysql数据库是存在硬盘中的,查询会磁盘I/O效率低,对数据库压力比较大,在实际业务中对购物车的操作很频繁。
2)本项目是使用redis来实现分布式锁的,在添加购物车和移除购物车时是和订单相关联的,为了保证订单数据的一致性,需要给购物车加锁
3)为了解决超卖问题,项目使用redis的automicLong来控制菜品库存,因为atomicLong操作是原子性。在项目中菜品库存的扣减,是使用redis来预扣的。
4)redis支持8种数据类型,可以满足存储各种数据结构的需要。
6.购物车数据类型是什么? key是什么? value是什么?
是使用Hash结构来存储的,主key是 “Applet:addToOrderItem:lock:+orderNo”(业务前缀+订单编号)辅key是菜品的id,value是orderItemVo(订单明细)。
7.什么是联锁?
在redis中就是RedissonMultiLock,即把key1、key2、key3……keyN放到一个list集合中,然后对List集合进行迭代循环加锁,直到所有的key都添加成功,解锁时就是再遍历对key释放锁。
8.添加购物车为什么需要添加 菜品和订单 加联锁?
原因一:在项目中添加和移除购物车时,会对菜品库存进行增减的操作,且为了解决超卖的问题,项目设计的时候采用redis进行预扣减操作,在预扣减中为了保证双写一致性,所以会对购物车的添加或删除菜品和订单加锁;
原因二:一个桌台只能有一个订单,所以为了避免在多并发环境中一下子会创建多个订单,在开桌创建订单时就对订单加锁了。所以在添加菜品和订单时避免重复的订单出现,需要加锁。
9.库存扣减的 时机?
**下单时扣减库存**<br /> 优点:不会占有库存<br /> 缺点:下单不一定可以买到菜品<br />**加购物车扣减库存**<br /> 优点:下单一定可以买到菜品<br /> 缺点:占用菜品库存,导致菜品滞销<br /> **延迟队列解决:**<br />**RabbitMQ的延时队列来解决,在创建消息时设置超时时间。**<br />如何选择思考<br />站在 消费者 角度考虑 ,<br /> 加购物车扣库存<br /> 站在 商家 角度考虑<br /> 下单时扣减库存<br /> 站在两个角度,同时兼顾两者利益<br /> 场景 jd、淘宝唯品会<br /> 恶意攻击问题<br />限制<br /> 前端<br /> 后端<br /> 常用两种库存扣减时机
10.添加和移除购物车 如何保证库存的一致性?(MySQL和Redis双写一致性问题)
是通过mysql的事务和redis的分布式锁来保证添加和移除购物车时库存的一致性的。
mysql和redis双写一致性存在四种情况:
1)mysql 成功 redis 成功;2) mysql 失败 redis 失败 这两种是一致的
3)mysql 成功 redis失败;4)mysql失败 redis成功 这两存在不一致。
在operationShoppingCart( )方法上添加@Transactional
注解开启数据库事务,在方法中调用getLock( )方法,对redis的中订单的key加锁,下一步继续调用tryLock( )方法给锁设置等待时间,有效时间和时间单位参数。当线程执行完吃方法后调用unlock( )方法释放锁。
11.下单操作业务流程是什么?
1.给添加的订单加锁
2.通过订单编号在mysql数据库查询可以核算订单项的list集合后由po转为vo对象,判断集合是否为空,为空new 一个ArrayList<>集合;
3.根据业务前缀和订单编号得到redis的key,根据key查询出购物车订单项的对象,再调用readAllValues( )方法,得到购物车订单项的List集合;
4.判断在购物车订单项的List集合是否为空,如果不为空合,遍历redis的List集合在for循环里设置一个标记(Boolean flag = false),嵌套mysql的可核算订单List集合的for循环;如果为空,把redis的可核算订单项保存或更新到mysql数据库中
5.判断菜品是否存在相等,相等保存和修改菜品数量,把标记改为true,使用break结束循环;如果全都不相等,在当前redis的购物车订单项添加新的菜品;
6.重新计算订单金额计算,如果有优惠价格以优惠价格进行计算
7.更新订单金额信息
8.清理redis购物车订单项目
9.释放锁
10.再次查询最新的订单数据
12.购物车订单项 和 可核算订单项的合并逻辑?
是基于开关思想和冒号排序算法的逻辑来实现redis中购物车订单项和数据库中可核算订单项的合并