Redis实战——优惠券秒杀(超卖问题)

news/2024/4/26 1:14:54/文章来源:https://blog.csdn.net/qq_59212867/article/details/128104693

1 实现优惠券秒杀功能

下单时需要判断两点:1.秒杀是否开始或者结束2.库存是否充足

所以,我们的业务逻辑如下

1. 通过优惠券id获取优惠券信息

2.判断秒杀是否开始,如果未返回错误信息

3.判断秒杀是否结束,如果已经结束返回错误信息

4.如果在秒杀时间内,判断库存是否充足

5.如果充足,扣减库存

6.创建订单信息,并保存到优惠券订单表中

  • 6.1 保存订单id
  • 6.2保存用户id
  • 6.3保存优惠券id

7.返回订单id

 

代码实现:(Service层实现类)

 

package com.hmdp.service.impl;import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.time.LocalDateTime;/*** <p>*  服务实现类* </p>** @author 虎哥* @since 2021-12-22*/
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService iSeckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Overridepublic Result seckillVoucher(Long voucherId) {//1.获取优惠券信息SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);//2.判断是否已经开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())){Result.fail("秒杀尚未开始!");}//3.判断是否已经结束if (voucher.getEndTime().isBefore(LocalDateTime.now())){Result.fail("秒杀已经结束了!");}//4.判断库存是否充足if (voucher.getStock() < 1) {Result.fail("库存不充足!");}//5.扣减库存boolean success = iSeckillVoucherService.update().setSql("stock = stock-1").eq("voucher_id",voucherId).update();if (!success){Result.fail("库存不充足!");}//6. 创建订单VoucherOrder voucherOrder = new VoucherOrder();//6.1添加订单idLong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);//6.2添加用户idLong userId = UserHolder.getUser().getId();voucherOrder.setUserId(userId);//6.3添加优惠券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);//7.返回订单idreturn Result.ok(orderId);}
}

2 超卖问题(重点)

我们先尝试在高并发的情况下运行上述代码。(使用jmx工具)

 下图是创建了两百个线程,在一瞬间发出优惠券请求

 

但是我们看聚合报告,发现异常值只有45.5%,按道理来说应该是50%(因为库存有100个,这里发出了200个请求) 

 

 一看库存数,好家伙,是-9

 

订单也是添加了109个,这显然发生了超卖的问题。 

 那么,为什么会发生这种问题呢?

看图说话:

按照我们正常的流程来走,就是线程1线查询完库存,然后扣减库存,这个时候线程2再来查询库存,扣减库存,这样是没问题的。

超卖的问题就出在,在订单1查询库存后,发现是1,但还没去扣减的时候,线程2也来查询库存,发现也是1,也进行了扣减(高并发的场景下)

 

这就导致了超卖的问题。 

对于这种高并发的问题,最常见的解决方法就是:上锁~

但锁又包括悲观锁和乐观锁。

悲观锁简单的讲就是:觉得线程一定会发生,然后在操作之前每个人先拿锁,你执行完后,在轮到下一个来执行(串行执行)

乐观锁 :就是乐观(认为线程安全一定不会发生),只要在每次对数据修改之前,判断其他线程是否对数据进行的修改来保证线程安全。

悲观锁较为简单,这里实现乐观锁。

乐观锁的关键是判断之前查询得到的数据是否有被修改过,常见的方式有两种

温馨提示:左边表格的数据都是线程1执行后的数据哦~

1.版本号法 

就是在查询库存的步骤上加上一个版本号,每次修改完数据后给版本号+1并在后面加上where条件判断版本号是否和修改前的一致

 

 这样就可以做到线程安全啦~        

2. CAS法

这个就是不用版本号了,直接在修改数据库后加上where条件判断库存是否是修改前的库存

解决超卖问题代码实现:

说到底就是在我们扣减库存的时候加上一个where条件判断库存是否大于0

 

package com.hmdp.service.impl;import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.time.LocalDateTime;/*** <p>*  服务实现类* </p>** @author 虎哥* @since 2021-12-22*/
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService iSeckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Overridepublic Result seckillVoucher(Long voucherId) {//1.获取优惠券信息SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);//2.判断是否已经开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())){Result.fail("秒杀尚未开始!");}//3.判断是否已经结束if (voucher.getEndTime().isBefore(LocalDateTime.now())){Result.fail("秒杀已经结束了!");}//4.判断库存是否充足if (voucher.getStock() < 1) {Result.fail("库存不充足!");}//5.扣减库存boolean success = iSeckillVoucherService.update().setSql("stock = stock-1").eq("voucher_id",voucherId).gt("stock",0).update();if (!success){Result.fail("库存不充足!");}//6. 创建订单VoucherOrder voucherOrder = new VoucherOrder();//6.1添加订单idLong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);//6.2添加用户idLong userId = UserHolder.getUser().getId();voucherOrder.setUserId(userId);//6.3添加优惠券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);//7.返回订单idreturn Result.ok(orderId);}
}

 超卖问题解决

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_38755.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

传奇登录器打不开的四种原因

最近很多传奇玩家或者GM都遇到了传奇登陆器打不开&#xff0c;没反应&#xff0c;提示无法访问指定设备等问题&#xff0c;导致很多游戏没有办法玩&#xff0c;让玩家心情沮丧&#xff0c;作为GM&#xff0c;那么就更伤心了&#xff0c;很多玩家进不来游戏&#xff0c;开服数千…

Maven笔记(2022-11-29)

一、Maven简述 1.1 什么是Maven&#xff1f; Apache Maven 是一款基于 Java 平台的项目管理和构建工具&#xff0c;它基于项目对象模型(POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建、报告和文档。 简单来讲Maven就是一个构建工具&#xff0c;用来管理我们的项目…

GMM算法

高斯混合模型聚类(Gaussian Mixture Mode&#xff0c;GMM) 高斯混合模型是一种概率式的聚类方法&#xff0c;它假定所有的数据样本x由k个混合多元高斯分布组合成的混合分布生成。 其中高斯分布的概率密度函数如下&#xff1a; 现在的问题就是如何求α,μ,σ\alpha,\mu,\sigm…

Spring-全面详解(学习总结---从入门到深化)

目录 Spring简介 Spring体系结构 IOC_控制反转思想 IOC_自定义对象容器 IOC_Spring实现IOC IOC_Spring容器类型 ​ 容器实现类 IOC_对象的创建方式 使用构造方法 使用工厂类的方法…

09【MyBatis多表关联查询】

文章目录三、MyBatis多表关联查询3.1 表的关系3.2 一对一查询3.2.1 搭建环境3.2.2 需求分析3.2.3 dao接口3.2.3 mapper.xml3.2.4 测试3.2.5 配置MyBatis一对一关系1&#xff09;传统映射&#xff1a;2&#xff09;使用association标签映射3.3 一对多查询3.3.1 需求分析3.3.2 da…

Kamiya丨Kamiya艾美捷大鼠微量白蛋白酶联免疫吸附试验说明书

Kamiya艾美捷大鼠微量白蛋白酶联免疫吸附试验预期用途&#xff1a; 大鼠微量白蛋白酶联免疫吸附试验&#xff08;ELISA&#xff09;是一种高灵敏度的双位点酶联免疫吸附试验&#xff08;ELISA&#xff09;大鼠生物样品中微量白蛋白的测定。仅供研究使用。 引言 白蛋白&#x…

SpringBoot、EasyPoi、Echarts 实现文档导入、出、图表显示 (饼状图、柱状图) 保姆级教程

一、介绍环境 EasyPOI: 现在我们就来介绍下EasyPoi,首先感谢EasyPoi 的开发者​。EasyPoi开源 easypoi 是为了让开发者快速的实现excel&#xff0c;word,pdf的导入导出&#xff0c;基于Apache poi基础上的一个工具包。easypoi教程 Echarts: …

转扩!寻找G2022次列车“旅客”

各位求职朋友大家好&#xff0c;欢迎乘坐G2022次列车 本次列车为6节编组&#xff0c;由上海开往北京&#xff0c;途径宁波、重庆 本次列车乘务组全体工作人员为您提供全方位福利待遇 上车地址&#xff1a;上海擎创信息技术有限公司 - 社会招聘 (eoitek.com) 如您还需其他帮助…

Java给图片增加水印,根据图片大小自适应,右下角/斜角/平铺

Hi&#xff0c;I’m Shendi 最近写自己的文件服务器&#xff0c;上传图片时需要自动增加水印&#xff0c;在这里记录一下 文章目录效果展示读取图片从 byte[] 读取图片获取画板绘制水印根据图片大小自适应水印大小右下角文字水印斜角水印平铺水印图片水印输出图片水印就是在图片…

SLAM学习笔记(二)

5.相机与图像 相机将三维世界中的坐标点&#xff08;单位米&#xff09;映射到二维图像平面&#xff08;单位为像素&#xff09;的过程中能够用一个几何模型进行描述。 单目相机(Mono)的成像过程&#xff1a; 1、世界坐标系下有个固定的点P&#xff0c;世界坐标为 2、由于相…

基于Java+SSM+Vue+ElementUi的汉语言类网上考试系统

项目介绍 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信…

前置微小信号放大器在光声技术的血管识别研究中的应用

实验名称&#xff1a;前置微小信号放大器在光声技术的血管识别研究中的应用 研究方向&#xff1a;生物识别技术 测试目的&#xff1a; 利用MATLAB对光声血管进行识别&#xff1a;1、对光声血管图库的图像进行预处理包括归一化、二值化、平滑、细化和毛刺修剪得到细化图像&#…

【安卓逆向】去除云注入(使用MT论坛dl的方法总结拓展)

1 需求 因为最近使用的虚拟机突然不能用了&#xff0c;被人云注入强制弹窗&#xff0c;如下图&#xff1a;&#xff08;这一看就是云注入了&#xff09; 2 大佬的方法 如图&#xff08;MT大佬分享的&#xff0c;感兴趣的朋友可以去大佬主页看看他其他文章&#xff09;&…

蓝海创意云接受【看苏州】独家专访:助力苏州数字文化行业全方位发展

近日&#xff0c;由蓝海创意云提供渲染服务的动漫电影《老鹰抓小鸡》获金鸡奖最佳美术片提名&#xff0c;位列获奖名单的《长津湖》《独行月球》也由蓝海创意云渲染提供了后期服务。 就此&#xff0c;苏州广播电视总台旗下的苏州权威热点新闻和视频平台【看苏州】对蓝海彤翔执…

[附源码]计算机毕业设计springboot基于Java的失物招领平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

用R Shiny生态快速搭建交互Web网页APP应用

什么是Shiny&#xff1f; Shiny包可以快速搭建基于R的交互网页应用。对于web的交互&#xff0c;之前已经有一些相关的包&#xff0c;不过都需要开发者熟悉网页编程语言&#xff08;html,CSS,JS&#xff09;。最近我们被客户要求撰写关于R Shiny的研究报告&#xff0c;包括一些…

快速复现 实现 facenet-pytorch 人脸识别 windows上 使用cpu实现 人脸对比

目录0 前言1 搭建环境与项目2 人脸预测与结果展示0 前言 这一次要复现的是人脸识别中的 facenet-pytorch 参考了&#xff1a; Pytorch 搭建自己的Facenet人脸识别网络&#xff08;Bubbliiiing 深度学习 教程&#xff09; https://gitee.com/xiaozhao123666/facenet-pytorch ht…

分布式消息中间件RabbitMQ解析

RabbitMQ作为分布式消息存储和转发系统&#xff0c;已广泛使用于分布式系统中。本文简要介绍RabbitMQ相关概念、集群架构和消息转发流程&#xff0c;并与Kafka做了简要对比&#xff0c;以加深理解。 1、RabbitMQ相关概念 1.1 AMQP介绍 消息&#xff08;Message&#xff09;是…

Zookeeper(一)- Zookeeper介绍与集群部署

文章目录一、Zookeeper 介绍1. Zookeeper概述2. Zookeeper工作机制3. Zookeeper特点4. Zookeeper数据结构5. Zookeeper应用场景&#xff08;1&#xff09;统一命名服务&#xff08;2&#xff09;统一配置管理&#xff08;3&#xff09;统一集群管理&#xff08;4&#xff09;服…

低代码与mes生产管理系统:功能篇

随着信息技术的发展和应用,信息系统在企业中的使用也越来越广泛。不仅可以使企业内部和企业间的信息流通更为便捷和频繁&#xff0c;同时可以提高管理的水平&#xff0c;有助于提高企业的生产效益。其中mes生产管理系统就是美豳的调查资询公司AMR(Advanced Manufacturing Resea…