首页 > 编程语言 >Java解决高并发秒杀商品

Java解决高并发秒杀商品

时间:2023-07-26 10:14:33浏览次数:38  
标签:库存 Java redis 并发 秒杀 操作 MQ 页面

在看本文章之前,需要了解Spring boot搭建和使用 ,本篇文章核心问题是如何解决高并发问题。

开发环境:redis缓存4.0.1,Rabbitmq消息队列,Erlang(这个跟MQ环境有关,先安装Erlang,再安装MQ),mysql5.7,JDK1.8(Spring boot要用1.8以上的版本)

开发框架:Spring boot 2.0.4 , mybatis,前端页面:thymeleaf展示信息

   

一:问题

首先我们要考虑的是为什么要解决高并发,高并发瓶颈出现在哪里,有了解过的朋友肯定知道是在数据库,因为在大量请求去操作数据库时会出现数据的错乱,超卖,系统崩溃,mysql死锁等现象。

二:思路

既然知道问题出现在哪之后,就要对症下药,减少对数据的访问。在这里提供一下解决思路:

1. 页面静态化:就是将整个页面存储到redis中,下次访问时去读取redis中的页面值

2. cdn:主要对整个网站的静态资源文件进行加速,如图片,css,js等(去阿里看教程)

3.数学验证码:用户在计算验证码结果时可以减少大量请求同时进入,减少redis, mysql,服务器的压力。

4:库存标识:这是一个巨大优化,通过标识来判断redis的库存是否足够,如不足就中断去读取redis库存。例:boolean over = map.get(goodsId);当我们map通过key读取到value值为true的时候,就返回错误提示给用户, if(over) { return Result.error(‘库存不足’); }.....这样不管以后有多个请求进入都只运行两行代码,以下的操作无法进入。

5.生成动态url:主要是防止恶意用户通过固定url进行提前秒杀商品(安全方面问题这个不可掉以轻心,你连安全措施都没做好以下的那些操作都是白搭的)

6. redis预减库存::在用户秒杀商品前去redis获取当前的库存数量,然后在秒杀时候直接减去redis存储的库存(大家放心这里Redis和MySQL数据是同步的,只要进入MQ队列操作完成下单,MySQL数据库会-1数量),从而避开去MySQL读取库存数据。

7. MQ消息队列:它是一个中间消息键,通过生产者发送消息给消费者,进行业务操作,而生产者无需知道执行结果,也就是用户点击秒杀之后等待处理结果,之后再去轮询查询处理结果(异步操作),这样就避开了不断请求去操作数据库。(这里的轮询查询也是直接从redis里面去查询,因为秒杀成功之后会将秒杀的结果放到redis中,轮询时候通过key去查询)

8. Nginx: 解决高并发的好方法,也就是我们多增加几个tomcat服务器。当用户访问的时候,请求可以提交到空闲的tomcat服务器上。

三:实现

1. 页面的静态化:很多人说怎么页面静态化,其实页面静态化就是将整个页面储到redis中,我们访问这个接口的时候就直接去获取redis的中页面,这样大大提高了访问页面的速度。如下图:

 

 

   

 

 

2. 预先获取秒杀商品信息,库存存储到redis中,怎么个预先法?在启动项目时在MiaoshaController调用InitializingBean接口,这个主要是在启动项目时去查询数据库中所有的秒杀商品的信息,库存等。大家别小看那一行标识代码,这可是一个巨大转折点的优化。为什么呢?接着看下去。如下图:

 

 

 

3. 数学公式验证码,这个也是减少大量请求的方法,因为你要去计算结果,想想几秒钟时间我可以减少多少访问请求,这个数学公司验证码自己去百度找下,同样把生成的验证码结果存储到redis中,判断时在去redis中获取结果对比验证码结果。

 

 

   

 

 

4.生成动态url,防止恶意用户提前秒杀商品! 我们应该先在访问秒杀业务时去生成一个动态的url,这样做可以防止恶意用户去通过固定url去提前秒杀商品。方法如下图:

html:

 

 

   

 

   

 

   

 

 

5.当我们生成动态Url之后,我们进行秒杀业务的操作,将我们的url传递到后台进行验证是否与之前所生存的一致,并且进行MQ消息队列处理请求 如下图:

 

 

   

 

 

我们执行完秒杀业务层之后,将结果0返回到js中,其实这时候mq已经异步进行操作去下订单操作了,js去轮询查询数据库中是否已经下订单成功,相当是说下订单操作和js去查询下订单信息是互不相关的,这也就说不管有没有秒杀是否成功都先返回一个0结果消息。当然这里还有个问题,就是我们如何区分秒杀的操作是在排队中呢还是库存已经秒杀完毕了呢?请接着继续看下去!

 

 

   

 

   

 

 

(异步操作,js查询和下订单各自执行)下面来重点将下MQ这个过程,在我们平时的超市中购物也是一样,当我们在结算的时候,并不会一窝蜂一样涌入收银台,而是排队结算。这也是队列机制。我们在使用MQ前先要去配置信息如下图:

 

 

 

然后我们在启动MQ时要自动加载定义通信消息,用于生产者发送消息给消费者的信息

 

 

e

当我们在执行秒杀业务验证都通过的话,生产者会发送一条"miaosha.queue"消息给消费者

 

 

 

当然消费者收到信息之后,进行秒杀下订单操作,不过为了数据正确性,这时候需要去数据库查询下当前的库存是否足够,而不是前面判断就可以了,前面redis判断只是为了减少mysql的访问。如下图:

 

 

 

这里我详细说下在下订单时,会出现向上面说怎么区分卖完了和排队中,假如秒杀商品被卖完了我们记录下,将商品Id当作K,true为V存储在redis中,在redis轮询查询的时候就可以判断是在排队还是商品卖完了。(没看明白的去看下轮询查询的代码)

 

 

   

 

 

在减库存的时候需要注意下sql语句 ,需要库存数量-1 并且库存数量必须>0才能操作下订单 ,至于添加订单详情数据我就不贴出来了,一般就是平常增加数据操作就行了,如下图:

 

 

 

还没有写完 。。。。。。。。还在更新完善中

我先给下源代码 :https://pan.baidu.com/s/1gpdFvcalAC53mq1L2BV3uw



作者:postman_4dc9
链接:https://www.jianshu.com/p/718b1147ee3a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:库存,Java,redis,并发,秒杀,操作,MQ,页面
From: https://www.cnblogs.com/zhc088/p/17581691.html

相关文章

  • Java面试题 P5:简述final作用
    1、简述final作用?final含义是最终的。(1)修饰类:表示类不可被继承,不可以有子类;(2)修饰方法:表示方法不可以被子类覆盖,但是可以重载;(3)修饰变量:表示变量一旦被赋值就不可以更改它的值。(4)修饰成员变量如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初......
  • 《安富莱嵌入式周报》第318期:无线电扫描仪,高精度功耗分析仪,单片机JavaScript引擎,平头
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 【实战技能视频】基于硬件垂直消隐的多缓冲技术在LVGL,emWin,GUIX和TouchGFX应用https://www.armbbs.cn/forum.php?mod=viewthread&tid=120114视频版:https://www.bilibili.......
  • springboot 解决高并发下的商品少卖多卖的问题
    1.商品秒杀-超卖在开发中,对于下面的代码,可能很熟悉:在Service里面加上@Transactional事务注解和Lock锁。控制层:Controller@ApiOperation(value="秒杀实现方式——Lock加锁")@PostMapping("/start/lock")public Result startLock(long skgId){    try {        ......
  • Java程序员进阶之路----四阶段
    第一阶段:JavaSE全面深入的学系JavaSE课程,主要内容包括Java概述与环境搭建、基本语法、面向对象基础、接口、抽象类、常用类(Object/内部类/包装类/String等)、集合、算法和数据结构、异常、多线程、I/O框架、网络编程、JDK8新特性、JVM内存模型、反射、注解xml等。本阶段学......
  • 学习Java第5天
    Java程序运行机制1.编译型(complie)操作要求不高(c....c++)2.解释性速度要求不高,(网页-脚本)3.程序运行机制psvm生成门方法sout生成输出语句IDEA的使用 ......
  • 面试类-Java并发编程 (一)
    1.并行跟并发有什么区别?从操作系统的角度来看,线程是CPU分配的最小单位。并行就是同一时刻,两个线程都在执行。这就要求有两个CPU去分别执行两个线程。并发就是同一时刻,只有一个执行,但是一个时间段内,两个线程都执行了。并发的实现依赖于CPU切换线程,因为切换的时间特别短,所以基本......
  • [爬虫]2.2.2 使用PhantomJS处理JavaScript
    PhantomJS是一个无头(headless)浏览器,它可以解析和执行JavaScript,非常适合用于爬取动态网页。"无头"意味着它可以在没有用户界面的情况下运行,这对于服务器环境和自动化任务非常有用。安装PhantomJS首先,你需要下载并安装PhantomJS。你可以从官方网站下载↗适合你的操作系统的版本......
  • java中关于多态的理解
    多态:是同一个行为具有多个不同表现形式或形态的能力。在代码的运用中主要是关于子类中方法的重写,实现了同一个父类接口可以进行不同子类中重写的方法publicclassGeometricOject{//父类publicdoublefindArea(){return0.0;}}publicclassCircleext......
  • LoadRunner 多机联合压测并突破并发
    模拟大量用户并发操作时,单台压力机无法满足要求,所以就需要进行多台联合进行压力测试。具体实施策略如下:设备:3台压力测试机或更多(根据用户量判断测试机台数,单个模拟用户占用内存2.5MB),其中一台做为主要主控机,其余为压力机,压力机均需要安装LoadRunner且使用管理员身份运行。1)设置......
  • Java面试常见问题总结
    Java面试常见问题总结Java基础Java中的几种基本数据类型是什么?对应的包装类型是什么?各自占用多少字节呢?String、StringBuffer和StringBuilder的区别是什么?String为什么是不可变的?Strings1=newString("abc");这段代码创建了几个字符串对象?==与equals?hashCo......