秒杀 预约活动项目中如何高效的保证下单交易成功?保证redis( 二 )


如果由redis预先缓存user信息,和item信息相当于在第一步校验下单的过程省去了两次查表,这就极大的提升了下单的速度 。
@TransactionalpromoId非空表示已预约活动价格下单public OrderModel createOrder(Integer userId, Integer itemId, Integer promoId,Integer amount,String stockLogId) throws BusinessException {//1.校验下单状态,商品是否存在,用户是否合法,购买数量是否正确verifyingUserInformation(itemId,userId,amount,promoId);//2.落单减库存,支付减库存orderDecreaseStock(itemId, amount);//3.订单入库OrderModel orderModel = orderintoMysql(itemId, userId, amount, promoId);//4.返回前端return orderModel;}/**负责createOrder中的用户校验工作*/private void verifyingUserInformation(Integer itemId, Integer userId,Integer amount,Integer promoId) throws BusinessException {//这一步是没有缓存的直接查mysqlItemModel itemModel = itemService.getItemById(itemId);//这一步是走缓存的ItemModel itemModel = itemService.getItemByIdInCache(itemId);if (itemModel == null) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "商品信息不存在");}/**这个地方如果采用token登录模式这个地方是不用放进redis中进行验证user信息的,他这个采用的是oss模型所以需要* 将用户信息缓存在redis中提高效率UserModel userModel = userService.getUserById(userId);*/UserModel userModel = userService.getUserByIdInCache(userId);if (userModel == null) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户信息不存在");}if (amount <= 0 || amount > 99) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "数量信息不正确");}//校验活动信息if (promoId != null) {//校验对应活动是否存在这个适用商品if (!promoId.equals(itemModel.getPromoModel().getId())) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动信息不正确");} else if (itemModel.getPromoModel().getStatus() != 2) {//活动是否正在进行中throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动还未开始");}}}
/**用于商品活动缓存设置,因为生成订单需要两部分,第一部分需要验证商品,第二部分要验证用户*/@Overridepublic ItemModel getItemByIdInCache(Integer id) {ItemModel itemModel = (ItemModel) redisTemplate.opsForValue().get("item_validate_" + id);if (itemModel == null) {itemModel = this.getItemById(id);redisTemplate.opsForValue().set("item_validate_" + id, itemModel);redisTemplate.expire("item_validate_" + id, 10, TimeUnit.MINUTES);}return itemModel;}
@Overridepublic UserModel getUserByIdInCache(Integer id) {UserModel userModel = (UserModel) redisTemplate.opsForValue().get("user_validate_"+id);if(userModel == null){userModel = this.getUserById(id);redisTemplate.opsForValue().set("user_validate_"+id,userModel);redisTemplate.expire("user_validate_"+id,10, TimeUnit.MINUTES);}return userModel;}
2.redis实现扣减库存优化
如果每次下单都需要去数据库中去减库存,这样又1w条请求来,都要查询去更改同一件商品的stock数量,会很慢 。因为在更改数据的时候会触发行锁 。这样其他线程请求就需要去等当前线程更改完数据库才能进行更改,效率太低了 。
代码
.xml
update item_stockset stock = stock - #{amount}where item_id = #{itemId} and stock >= #{amount}
如果我们直接用redis来进行更下单扣减库存操作呢?
1、redis先从数据库中取出库存数量
2、有下单请求时,每次来的请求都去扣减redis中的数量(因为redis是内存级别的效率非常高) 。