秒杀/高并发解决方案+落地实现

article/2025/9/5 8:25:49
  1. 前面我们防止超卖 是通过到数据库查询和到数据库抢购,来完成的, 代码如下:

  1. 如果在短时间内,大量抢购冲击 DB, 造成洪峰, 容易压垮数据库
  2. 解决方案:使用 Redis 完成预减库存,如果没有库存了,直接返回,减小对 DB 的压力。
  3. 图示:

Redis 的预减,已经存在了原子性,就是一条一条执行的,不会存在,复购,多购的可能性。

修改 SeckillController.java 实现 InitializingBean 接口,

InitializingBean 当中的 afterPropertiesSet 表示项目启动就自动给执行该方法当中的内容

package com.rainbowsea.seckill.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rainbowsea.seckill.pojo.Order;
import com.rainbowsea.seckill.pojo.SeckillOrder;
import com.rainbowsea.seckill.pojo.User;
import com.rainbowsea.seckill.service.GoodsService;
import com.rainbowsea.seckill.service.OrderService;
import com.rainbowsea.seckill.service.SeckillOrderService;
import com.rainbowsea.seckill.vo.GoodsVo;
import com.rainbowsea.seckill.vo.RespBeanEnum;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;import javax.annotation.Resource;
import java.util.List;@Controller
@RequestMapping("/seckill")
// InitializingBean 当中的 afterPropertiesSet 表示项目启动就自动给执行该方法当中的内容
public class SeckillController implements InitializingBean {// 装配需要的组件/对象@Resourceprivate GoodsService goodsService;@Resourceprivate SeckillOrderService seckillOrderService;@Resourceprivate OrderService orderService;@Resourceprivate RedisTemplate redisTemplate;/*** 方法: 处理用户抢购请求/秒杀* 说明: 我们先完成一个 V3.0版本,* - 利用 MySQL默认的事务隔离级别【REPEATABLE-READ】* - 使用 优化秒杀: Redis 预减库存+Decrement** @param model   返回给模块的 model 信息* @param user    User 通过用户使用了,自定义参数解析器获取 User 对象,* @param goodsId 秒杀商品的 ID 信息* @return 返回到映射在 resources 下的 templates 下的页面*/@RequestMapping(value = "/doSeckill")public String doSeckill(Model model, User user, Long goodsId) {System.out.println("秒杀 V 2.0 ");if (null == user) { //用户没有登录return "login";}// 登录了,则返回用户信息给下一个模板内容model.addAttribute("user", user);// 获取到 GoodsVoGoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);// 判断库存if (goodsVo.getStockCount() < 1) {  // 没有库存,不可以购买model.addAttribute("errmsg", RespBeanEnum.ENTRY_STOCK.getMessage());return "secKillFail"; // 返回一个错误页面}// 判断用户是否复购-直接到 Redis 当中获取(因为我们抢购成功直接// 将表单信息存储到了Redis 当中了。 key表示:order:userId:goodsId  Value表示订单 seckillOrder),// 获取对应的秒杀订单,如果有,则说明该// 用户已经桥抢购了,每人限购一个SeckillOrder o = (SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" +goodsVo.getId()); // 因为我们在 Redis 当中的 value值就是 SeckillOrder 订单对象,所以这里可以直接强制类型转换if (null != o) { // 不为null,说明 Redis 存在该用户订单信息,说明该用户已经抢购了该商品model.addAttribute("errmsg", RespBeanEnum.REPEAT_ERROR.getMessage()); // 将错误信息返回给下一页的模板当中return "secKillFail"; // 返回一个错误页面}// Redis库存预减,如果在 Redis 中预减库存,发现秒杀商品已经没有了,就直接返回// 从面减少去执行 orderService.seckill()请求,防止线程堆积,优化秒杀/高并发// 提示: Redis 的 decrement是具有原子性的,已经存在了原子性,就是一条一条执行的,不会存在,复购,多购的可能性。// 注意:这里我们要操作的 key 的是:seckillGoods:商品Id,value:该商品的库存量Long decrement = redisTemplate.opsForValue().decrement("seckillGoods:" + goodsId);if (decrement < 0) {  // 说明这个商品已经没有库存了,返回// 这里我们可以恢复库存为 0 ,因为后面可能会一直减下去,恢复为 0 让数据更好看一些redisTemplate.opsForValue().increment("seckillGoods:" + goodsId);model.addAttribute("errmsg", RespBeanEnum.REPEAT_ERROR.getMessage()); // 将错误信息返回给下一页的模板当中return "secKillFail"; // 返回一个错误页面}// 抢购Order order = orderService.seckill(user, goodsVo);if (order == null) { // 说明抢购失败了,由于什么原因model.addAttribute("errmsg", RespBeanEnum.ENTRY_STOCK.getMessage());return "secKillFail"; // 返回一个错误页面}// 走到这里,说明抢购成功了,将信息,通过 model 返回给页面model.addAttribute("order", order);model.addAttribute("goods", goodsVo);System.out.println("秒杀 V 2.0 ");return "orderDetail";  // 进入到订单详情页}/*** InitializingBean 接口当中的 afterPropertiesSet 表示项目启动就自动给执行该方法当中的内容* 该方法是在类的所有属性,都是初始化后,自动执行的* 这里我们就可以将所有秒杀商品的库存量,加载到 Redis 当中** @throws Exception*/@Overridepublic void afterPropertiesSet() throws Exception {// 获取所有可以秒杀的商品信息List<GoodsVo> list = goodsService.findGoodsVo();// 先判断是否为空if (CollectionUtils.isEmpty(list)) {return;}// 遍历 List,然后将秒杀商品的库存量,放入到 Redis// key:秒杀商品库存量对应 key:seckillGoods:商品Id,value:该商品的库存量list.forEach(goodsVo -> {redisTemplate.opsForValue().set("seckillGoods:" + goodsVo.getId(), goodsVo.getStockCount());});

http://www.hkcw.cn/article/IlyqAZLIUf.shtml

相关文章

Baklib企业知识激活解决方案

Baklib知识中台构建路径 Baklib通过模块化架构设计与智能数据治理双轮驱动&#xff0c;为企业构建知识中台提供标准化实施路径。首先基于自然语言处理&#xff08;NLP&#xff09;技术实现非结构化文档的语义解析&#xff0c;打通CRM、ERP等业务系统间的数据孤岛&#xff1b;随…

【Gemini 深度研究】人形机器人:最新开发方案与未来展望 (2024-2025)

Gemini根据深度研究报告自动生成的html网页录屏 人形机器人&#xff1a;最新开发方案与未来展望 (2024-2025) I. 执行摘要 2024年至2025年&#xff0c;人形机器人正处于从科研探索向实际应用转型的关键时期&#xff0c;其作为通用型机器人的潜力日益显现。这一转变主要得益于具…

【动态规划:斐波那契数列模型】第 N 个泰波那契数

1、第 N 个泰波那契数&#xff08;easy&#xff09; 1137. 第 N 个泰波那契数 泰波那契序列 Tn 定义如下&#xff1a; ​ T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2。给你整数 n&#xff0c;请返回第 n 个泰波那契数 Tn 的值。 示例 1&#xff1a; …

秋招Day11 - JVM - JVM调优

性能监控的命令行工具&#xff1f; 操作系统层面&#xff1a; 我用过top来查看cpu和内存的使用情况使用过vmstat查看过虚拟内存的统计信息使用过iostat查看过系统的io情况使用过netstat查看过系统的网络信息 JDK自带的命令层面&#xff0c;我使用过&#xff1a; jmap -heap…

ChatGPT Plus/Pro 订阅教程(支持支付宝)

订阅 ChatGPT Plus GPT-4 最简单&#xff0c;成功率最高的方案 1. 登录 chat.openai.com 依次点击 Login &#xff0c;输入邮箱和密码 2. 点击升级 Upgrade 登录自己的 OpenAI 帐户后&#xff0c;点击左下角的 Upgrade to Plus&#xff0c;在弹窗中选择 Upgrade plan。 如果…

【深度学习】12. VIT与GPT 模型与语言生成:从 GPT-1 到 GPT4

VIT与GPT 模型与语言生成&#xff1a;从 GPT-1 到 GPT4 本教程将介绍 GPT 系列模型的发展历程、结构原理、训练方式以及人类反馈强化学习&#xff08;RLHF&#xff09;对生成对齐的改进。内容涵盖 GPT-1、GPT-2、GPT-3、GPT-3.5&#xff08;InstructGPT&#xff09;、ChatGPT …

笔试模拟 day14

观前提醒&#xff1a; 笔试所有系列文章均是记录本人的笔试题思路与代码&#xff0c;从中得到的启发和从别人题解的学习到的地方&#xff0c;所以关于题目的解答&#xff0c;只是以本人能读懂为目标&#xff0c;如果大家觉得看不懂&#xff0c;那是正常的。如果对本文的某些知…

基于照片环境信息的AI定位技术:从原理到实战的深度解析

基于照片环境信息的AI定位技术&#xff1a;从原理到实战的深度解析 摘要 本文聚焦基于照片环境信息的AI定位技术&#xff0c;系统梳理其核心原理、技术实现路径及行业应用场景。结合多模态融合、深度学习优化等前沿技术&#xff0c;分析如何通过AI训练提升定位精度&#xff0c…

NumPy 2.x 完全指南【二十二】数组标量

文章目录 1. 标量&#xff08;Scalar &#xff09;2. 数组标量&#xff08;Array Scalar&#xff09;3. 标量类型3.1 基类3.1.1 generic3.1.2 number3.1.3 flexible 3.2 整数类型3.2.1 有符号整数3.2.2 无符号整数 3.3 不精确类型3.3.1 浮点数3.3.2 复数 3.4 其他类型3.4.1 布尔…

外地车在北京进京证用完后该如何行驶

外地车在北京进京证用完后该如何行驶 这个问题想必非京籍的车友都有这样的困惑吧 作为一名资深外地车主&#xff0c;已在北京漂泊了13年之久&#xff0c;12次进京证的办理根本不够用&#xff0c;也有网友支招说和家人来回过户200搞定&#xff0c;多出12次&#xff0c;奈何这种…

可靠数据传输原理

目录 构造可靠数据传输协议 一、rdt1.0&#xff1a;理想信道下的可靠传输 核心假设与功能 二、rdt 2.0&#xff1a;带差错检测的停等协议 核心假设与功能 三、rdt 2.1&#xff1a;修复 ACK/NAK 不可靠性 核心改进 四、rdt 2.2&#xff1a;纯 ACK 实现的可靠传输 核心改…

JAVA重症监护系统源码 ICU重症监护系统源码 智慧医院重症监护系统源码

智慧医院重症监护系统源码 ICU重症监护系统源码 开发语言&#xff1a;JavaVUE ICU护理记录&#xff1a;实现病人数据的自动采集&#xff0c;实时记录监护过程数据。支持主流厂家的监护仪、呼吸机等床旁数字化设备的数据采集。对接检验检查系统&#xff0c;实现自动化录入。喜…

新版LangChain向量数据库VectorStore设计详解

导读&#xff1a;在大型语言模型与知识库集成的实践中&#xff0c;向量数据库的选择和架构设计往往成为项目成败的关键因素。本文深入剖析了LangChain框架中VectorStore的核心设计理念&#xff0c;为开发者提供了系统性的技术指导和实践方案。 文章揭示了LangChain如何通过抽象…

Transformer架构核心流程解析

Transformer的核心流程 Tokenizer→Embedding→Attention→FFN 1. 文本预处理与分词阶段&#xff08;Tokenizer&#xff09; 分词方式演进 基于单词的分词器&#xff1a;通过空格、标点符号拆分&#xff0c;但词汇表庞大且易出现未知词&#xff08;UNK&#xff09;基于字符…

【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN

【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN 目录 【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-LSTM、Transformer、CNN-LSTM、LSTM、…

美国华盛顿州一公园发生枪击事件 7人受伤

美国华盛顿州一公园在5月28日晚间发生枪击事件,导致7人受伤,其中3人伤势严重。警方表示,目前尚不清楚有多少嫌疑人参与了这起事件,并且截至事发当日,还没有任何人被逮捕。责任编辑:zx0176

RabbitMQ项目实战

先参考文章&#xff1a;&#xff08;必看&#xff09; 06-MQ基础_mq服务-CSDN博客 07-MQ高级&#xff08;幂等性&#xff09;-CSDN博客 https://cloud.iocoder.cn/message-queue/rabbitmq/#_2-0-%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96%E4%B8%8E%E9%85%8D%E7%BD%AE 1、Rabbi…

自动化测试实例:Web登录功能性测试(无验证码)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是自动化测试 把人为驱动的测试行为转化为机器执行的一种过程称为自动化测试。(来自百度百科)本质上来说&#xff0c;自动化测试对比起手工测试除了需…

用 Python 模拟下雨效果

用 Python 模拟下雨效果 雨天别有一番浪漫情怀&#xff1a;淅淅沥沥的雨滴、湿润的空气、朦胧的光影……在屏幕上也能感受下雨的美妙。本文将带你用一份简单的 Python 脚本&#xff0c;手把手实现「下雨效果」动画。文章深入浅出&#xff0c;零基础也能快速上手&#xff0c;完…

[PyTest-案例]

接口对象封装 1.requests和pymysql实现ihrm登录接口缺点 : 代码冗余度高,耦合度高,维护成本大 核心思想 : 代码分层 按代码功能划分 : 接口对象层 : 负责发送http请求,访问待测接口,返回响应数据测试用例层 : 调用接口,按照响应数据,断言完成测试 封装tpshop商城 普通方式…