Redis实现商品秒杀

2023-11-12

随着互联网的发展和消费者的需求越来越高,商品的销售也变得越来越激烈。而对于商家来说,最直观的解决方式即为促销活动。然而,促销活动也会引发一定的风险。如果处理得不当,可能会出现“抢购”活动中的库存不足等问题。本文将利用Redis实现商品秒杀,来避免这些问题的发生。

技术栈

本次实现采用的技术栈如下:

  • SpringBoot
  • Redis
  • Mybatis-plus
  • Vue

功能实现步骤

在实现商品秒杀之前,我们需要先准备好基本的开发环境。本文将假定您已经设置好了相关环境。

接下来,请按照以下步骤进行功能的实现。

步骤一:准备商品库存数据

首先,我们需要在数据库中创建一个名为“goods”的表,用于存储商品的库存数据。表结构如下:

CREATE TABLE `goods` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '秒杀商品ID',
  `goods_name` varchar(32) DEFAULT NULL COMMENT '商品名称',
  `goods_count` int(11) DEFAULT NULL COMMENT '商品库存数量',
  `start_time` datetime DEFAULT NULL COMMENT '秒杀开始时间',
  `end_time` datetime DEFAULT NULL COMMENT '秒杀结束时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在表中添加一些假数据,用于测试秒杀功能。

步骤二:实现商品秒杀

接下来,我们需要实现商品秒杀功能。这里,我们采用Redis作为秒杀的核心工具,通过前后端协作来实现秒杀。

1. Redis实现秒杀

在Redis中,我们可以使用List类型来存储待秒杀的商品ID,使用Set类型来存储已经秒杀成功的商品ID。同时,为了防止一个用户重复抢购同一个商品,我们还需要使用Hash类型来存储每个用户的秒杀订单信息。

具体实现方式如下:

  1. 初始化Redis中的商品列表和已秒杀商品集合,将数据库中的商品库存数量存入Redis中。
// 商品列表名称
String redisKey = "goods:" + seckillGoods.getId();
// 添加所有库存商品
for (int i = 0; i < seckillGoods.getGoodsCount(); i++) {
    redisTemplate.opsForList().rightPush(redisKey, String.valueOf(seckillGoods.getId()));
}
  1. 判断用户是否已经秒杀成功过。
// 查询用户是否已经秒杀过该商品
Object orderObj = redisTemplate.opsForHash().get("seckill_orders", seckillUser.getId() + ":" + seckillGoods.getId());
if (orderObj != null) {
    throw new SEckillException(ErrorCodeEnum.REPEAT_SEC_KILL_ERROR);
}
// 查询用户是否在排队中
Object userInQueueObj = redisTemplate.opsForSet().isMember("seckill_queues:" + seckillGoods.getId(), seckillUser.getId());
if (userInQueueObj != null) {
    throw new SEckillException(ErrorCodeEnum.WAITING_IN_QUEUE_ERROR);
}
  1. 利用Redis的事务实现处理抢购成功的逻辑。
// 开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.multi();
// 从商品列表中弹出一个商品
redisTemplate.opsForList().leftPop(redisKey);
// 利用setValueAt等方法,获取用户信息和商品信息,此处略过
// 判断是否获取到商品信息
if (seckillGoods == null) {
    redisTemplate.discard();
    throw new SEckillException(ErrorCodeEnum.SEC_KILL_FINISH_ERROR);
}
// 秒杀成功,生成秒杀订单
redisTemplate.opsForHash().put("seckill_orders", seckillUser.getId() + ":" + seckillGoods.getId(), seckillOrder);
// 秒杀成功的商品写入Set中
redisTemplate.opsForSet().add("seckill_success:" + seckillGoods.getId(), String.valueOf(seckillGoods.getId()));
// 提交事务
redisTemplate.exec();

以上代码,通过将Redis事务化实现了秒杀成功时,商品列表从一个元素弹出、将秒杀订单存入Hash中,以及在已秒杀商品集合中添加记录。当秒杀失败时,Redis将自动回滚整个事务。

2. 前端页面实现秒杀

在前端页面中,我们需要使用Vue同时发送两个请求,一个请求用于获取商品详情,另一个请求用于提交秒杀订单。具体实现方式如下:

  1. 获取商品详情。
created() {
    // 发送请求获取商品详情信息
    axios.get('/seckill/goods/' + this.$route.params.id)
        .then(res => {
            this.goods = res.data;
        })
        .catch(err => {
            console.log(err);
        })
}
  1. 提交秒杀订单。
seckill() {
    // 发送秒杀请求
    axios.post('/seckill/order/' + this.goods.id)
        .then(res => {
            if (res.data.code == 200) {
                alert('秒杀成功!');
            } else {
                alert(res.data.msg);
            }
        })
        .catch(err => {
            console.log(err);
        })
}

以上代码,通过使用Axios向后端发送商品详情和秒杀请求来实现秒杀功能。

步骤三:优化Redis性能

在实际的项目中,我们需要考虑如何优化Redis性能。以下是一些优化配置方案:

  • 增加Redis实例的数量以提高可用性和性能。
  • 设置Redis缓存的过期时间,防止内存泄漏和Redis存储空间的浪费。
  • 使用Redis的集群功能,将数据分散在多个Redis节点上,以提高Redis的容错性。

技术讲解

接下来,让我们来更加详细地讲解一下这个项目的实现技术和原理。

Redis的List类型

在实现商品秒杀时,我们需要用到Redis的List类型来存储待秒杀的商品ID,以及使用左边出队和右边进队等操作来模拟抢购的过程。

Redis的List类型是一个双向链表结构,可以在头部、尾部、任意位置插入、删除数据。使用List类型可以实现类似队列和栈的功能。

以下是使用Redis的List类型的一些命令:

  • LPUSH:在列表的左边插入一个或多个元素。
  • RPUSH:在列表的右边插入一个或多个元素。
  • LPOP:从列表的左边移除并返回一个元素。
  • RPOP:从列表的右边移除并返回一个元素。
  • LINDEX:返回列表中指定索引位置的元素。
Redis的Set类型

在实现商品秒杀时,我们还需要使用Redis的Set类型来存储已经秒杀成功的商品ID。

Redis的Set类型是一个无序集合,可以存储多个字符串类型的元素。Set类型支持去重和集合操作。

以下是使用Redis的Set类型的一些命令:

  • SADD:将一个或多个元素添加到集合中。
  • SREM:从集合中移除给定元素。
  • SCARD:返回集合的元素数量。
  • SMEMBERS:返回集合中的所有元素。
  • SISMEMBER:判断元素是否在集合中。
Redis的Hash类型

在实现商品秒杀时,我们还需要使用Redis的Hash类型来存储每个用户的秒杀订单信息。

Redis的Hash类型是一个字典结构,可以在O(1)时间内存储、修改和查询元素。

以下是使用Redis的Hash类型的一些命令:

  • HSET:设置哈希表中指定字段的值。
  • HGET:获取哈希表中指定字段的值。
  • HGETALL:获取哈希表中所有字段和值。
  • HDEL:删除哈希表中一个或多个字段。
  • HEXISTS:判断哈希表中指定字段是否存在。
Redis的事务

在实现商品秒杀时,我们需要保证秒杀成功时商品列表中需要弹出一个元素、同时将秒杀订单信息存入Hash中,并且在已秒杀商品集合中添加记录。为了保证这三个操作同时完成,我们需要使用Redis的事务来保证原子性。

Redis的事务是一组命令的集合,这些命令会被一次性、按照顺序地执行。在执行事务期间,其他客户端的操作不会干扰该事务的执行。

以下是使用Redis事务的一些命令:

  • MULTI:开启事务。
  • EXEC:提交事务,执行事务中的所有命令。
  • DISCARD:撤销事务。
Mybatis-plus

在本项目中,我们使用了Mybatis-plus作为ORM框架来操作数据库。Mybatis-plus是Mybatis的增强版本,可以大幅度提高开发效率。

Mybatis-plus的一些特点如下:

  • 无需编写Mapper接口,可以使用自动生成的通用Mapper接口对数据库进行操作。
  • 支持Lambda表达式,可改善代码可读性。
  • 丰富的查询条件API,支持链式调用。

本项目中用到的一些Mybatis-plus的注解如下:

  • @TableName:指定实体类对应的数据库表名。
  • @TableField:指定实体类字段对应的数据库列名。
  • @Autowired:在Spring中自动装配需要使用的Bean。

开发流程

开发流程如下:

  1. 准备项目环境,包括SpringBoot、Redis、Mybatis-plus、Vue等组件。
  2. 在数据库中创建秒杀商品表seckill_goods,并添加一些测试数据。
  3. 根据实际需求,在后端代码中实现商品秒杀功能,其中需要用到Redis的List、Set和Hash类型,以及使用Redis事务保证原子性。
  4. 在前端页面中使用Vue,向后端发送商品详情和秒杀请求,实现商品秒杀。
  5. 优化Redis性能,增加Redis实例的数量、设置缓存过期时间和使用Redis集群等方式。
  6. 测试和部署项目。

小结

本文介绍了如何使用Redis实现商品秒杀,并提供了详细的功能实现步骤和技术讲解。在实现过程中,我们了解了Redis的List、Set和Hash类型,以及使用Redis事务保证原子性的方式。同时,我们也使用了Mybatis-plus作为ORM框架,有效提高了开发效率。最后,我们还介绍了如何优化Redis性能,进一步提升了项目的质量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis实现商品秒杀 的相关文章

  • 使用 Tabula 通过 Python 读取 pdf 时出现 Java 错误

    我已经安装了 tabula 库 用于使用 python 将 pdf 读取到 pandas 数据框中 但是当我运行代码时 import tabula df tabula read pdf sample1 pdf pages 1 我得到了例外
  • 如何在由子控件组成的 SWT 复合材料上跟踪鼠标?

    我创建了自己的控件 我想跟踪鼠标并添加一个MouseTrackListener 很遗憾MouseEnter and MouseLeave当鼠标移动到我的合成部分 即标签和按钮 上时 也会生成事件 Mouse enter mouse ente
  • 有没有创建 Cron 表达式的 Java 代码? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我需要一个 Java 代码来根据用户输入创建一个 cron 表达式 用户输入是时间 频率和执行次数 只需从评论中添加 自己创建 即可
  • Java Logger 未记录到 Netbeans 中的输出

    我正在 Netbeans 中使用 Maven 启动一个 Java 项目 我编写了一些代码来使用 Logger 类进行日志记录 但是 日志记录似乎不起作用 在程序开始时 我运行 Logger getLogger ProjectMainClas
  • java.lang.ClassNotFoundException:javax.mail.MessagingException

    我想使用 eclipse 将电子邮件从我的 gmail 帐户发送到另一个邮件帐户 我使用 apache tomcat 7 0 34 作为我的 Web 服务器 并使用端口 8080 作为 apache 服务器 HTTP 1 1 并使用 JRE
  • 两个整数乘积的模

    我必须找到c c a b mod m a b c m 是 32 位整数 但 a b 可以超过 32 位 我正在尝试找出一种计算 c 的方法 而不使用 long 或任何 gt 32 位的数据类型 有任何想法吗 如果m是质数 事情可以简化吗 注
  • Android:文本淡入和淡出

    我已阅读此 stackoverflow 问题和答案 并尝试实现文本淡入和淡出 Android中如何让文字淡入淡出 https stackoverflow com questions 8627211 how to make text fade
  • 为什么即使我的哈希码值相同,“==”也会返回 false

    我写了一个像这样的课程 public class HashCodeImpl public int hashCode return 1 public static void main String args TODO Auto generat
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • Jframe 内有 2 个 Jdialogs 的 setModal 问题

    当我设置第一个选项时 我遇到了问题JDialog模态 第二个非模态 这是我正在尝试实现的功能 单击 测试对话框 按钮 一个JDialog有名字自定义对话框 主要的将会打开 如果单击 是 选项自定义对话框主 其他JDialog named 自
  • Runtime.exec 处理包含多个空格的参数

    我怎样才能进行以下运行 public class ExecTest public static void main String args try Notice the multiple spaces in the argument Str
  • 如何在单个查询中搜索 RealmObject 的 RealmList 字段

    假设我有一堂课 public class Company extends RealmObject private String companyId private RealmList
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • 提高 PostgreSQL 1 亿数据左连接查询性能

    我在用Postgresql 9 2 version Windows 7 64 bit RAM 6GB 这是一个Java企业项目 我必须在我的页面中显示订单相关信息 有三个表通过左连接连接在一起 Tables TV HD 389772 行 T
  • 蓝牙发送和接收文本数据

    我是 Android 开发新手 我想制作一个使用蓝牙发送和接收文本的应用程序 我得到了有关发送文本的所有内容逻辑工作 但是当我尝试在手机中测试它时 我看不到界面 这是Main Activity Code import android sup
  • 如何将 HTML 链接放入电子邮件正文中?

    我有一个可以发送邮件的应用程序 用 Java 实现 我想在邮件中放置一个 HTML 链接 但该链接显示为普通字母 而不是 HTML 链接 我怎样才能将 HTML 链接放入字符串中 我需要特殊字符吗 太感谢了 Update 大家好你们好 感谢
  • 轻松的反应

    我有一个与这里描述的类似的案例 动态更改RESTEasy服务返回类型 https stackoverflow com questions 3786781 dynamically change resteasy service return
  • 部署 .war 时出现 Glassfish 服务器错误:部署期间发生错误:准备应用程序时出现异常:资源无效

    我正在使用以下内容 NetBeans IDE 7 3 内部版本 201306052037 爪哇 1 7 0 17 Java HotSpot TM 64 位服务器虚拟机 23 7 b01 NetBeans 集成 GlassFish Serve
  • java 中的蓝牙 (J2SE)

    我是蓝牙新手 这就是我想做的事情 我想获取连接到我的电脑上的蓝牙的设备信息并将该信息写入文件中 我应该使用哪个 api 以及如何实现 我遇到了 bluecove 但经过几次搜索 我发现 bluecove 不能在 64 位电脑上运行 我现在应
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何

随机推荐

  • wireshark流量分析网络安全

    目录 前言 题目1 题目2 题目3 题目4 题目5 题目6 题目7 题目8 前言 这是关于一篇wireshark分析数据包的文章 主要是网络安全里的应用 讲述了wireshark的使用方法 主要使用的事wrieshark里的追踪流 欢迎大家
  • elementUI 下拉框select 为多选 赋值回显问题

    下拉框为多选时 绑定的值为数组状态 所以点击编辑赋值时 需要处理为数组 但我遇到的问题是 可以赋值 但不是想要的结果 我想要显示label 但显示的是value 不想得到的效果 想要的是 在赋值后面加 map Number 就可以对号入座了
  • 【翻译】 使用 SFrame 进行可靠的用户空间堆栈跟踪

    请考虑订阅 LWN订阅是 LWN net 的生命线 如果您喜欢这些内容并希望看到更多 您的订阅将有助于确保 LWN 继续蓬勃发展 请访问此页面加入我们 让 LWN 继续在网络上传播 作者 Jonathan Corbet 2023 年 5 月
  • html页面传list,后端list集合中的数据传递到前台HTML中显示(表格形式)

    关键字 web项目中前后台数据传递问题 在学习web项目的过程中 我们肯定会遇到前后台数据交换问题 这个问题我也思考了很久 今天借此总结一下 由于博主水平有限 如有不当之处 还请大家多多指正 废话不所说进入正题 一 HTML页面通过ajax
  • 《Thinking_in_java_4th》持续输出中.......

    目录标题 一 文章目录 二 源码链接 一 文章目录 Java设计者们说过 设计这门语言的灵感主要来自C Java编程思想 第 2章 一切都是对象 Java编程思想 第 4章 控制执行流程 Java编程思想 第14章 类型信息 Java编程思
  • 排名前 16 的 Java 工具类

    原链接 https mp weixin qq com s s6IfovcE LGlZJxIKfT dw 目录 org apache commons io IOUtils org apache commons io FileUtils org
  • 磁耦隔离与传统隔离的区别

    磁耦隔离与传统隔离的区别 传统隔离技术 传统的隔离方式有哪些 这里有三种通常的隔离技术 光电隔离 变压器隔离 磁耦是芯片级变压器隔离技术 电容隔离 在体积 成本 性能等各方面都有优缺点 传统的隔离方式是光电隔离 什么是光耦 什么是光隔离 光
  • Qt GraphicsView框架中实现多个item之间的层次调整功能

    目的 要实现GraphicsView中多个item之间的层次调整功能 即 选中的item可以实现 移动至顶层 移动至底层 上移一层 下移一层 等功能 之前盲目地认为Qt API会提供 获取与之相邻的sibling item 类似这样的接口
  • 2023全新SF授权系统源码 V3.7全开源无加密版本,亲测可用

    2023全新SF授权系统源码 V3 7全开源无加密版本 网站搭建很简单 大致看来一下应该域名解析后上传源码解压 访问域名 install就能直接安装 程序功能简介 1 盗版入库 26种 2 快捷登录 3 采用layuiadmin框架 4 易
  • ASP.NET core MVC动作过滤器执行顺序

    using Microsoft AspNetCore Mvc Filters using System using System Threading Tasks namespace dotnet core Filter public cla
  • 两片74161实现60进制_74LS161设计60进制计数器-数电课程设计

    计数器是一个用以实现计数功能的时序部件 它不仅可用来及脉冲数 还常用作数子系统的定时 分频和执行数字运算以及其它特定的逻辑功能 计数器种类很多 按构成计数器中的各触发器是否使用一个时钟脉冲源来分 有同步计数器和异步计数器 根据计数制的不同
  • js怎么改变样式中的属性值

    可以使用JavaScript来改变HTML元素的样式属性值 具体方法如下 通过id属性获取要修改的元素对象 var obj document getElementById element id 修改元素的样式属性值 obj style pr
  • 错误: 至少有一个需要的隐性或转发依赖函数没找到。_【翻译】自动柯里化Rust函数...

    原文标题 Auto currying Rust Functions 原文链接 https peppe rs posts auto currying rust functions 公众号 Rust碎碎念 本文包含Rust中过程宏 proced
  • 《疯狂Java讲义》读书笔记(一):面向对象,数据类型和运算符,流程控制与数组

    序言 疯狂Java讲义 这本书深入介绍了Java编程的相关方面 全书内容覆盖了Java的基本语法结构 Java的面向对象特征 Java集合框架体系 Java泛型 异常处理 JavaGUI编程 JDBC数据库编程 Java注释 Java的IO
  • Yii Framework 开发教程(6) CComponent 组件

    在Hangman中定义的GameController使用到一些属性word 可以使用 this gt word 的格式来读写这个属性 但实际上在GameController对应到这个属性的方法为 php view plain copy pr
  • 机器学习之集成学习

    一 介绍 集成学习 Ensemble Learning 是一种机器学习技术 通过结合多个学习器 例如决策树 神经网络 支持向量机等 的预测结果 来达到更好的分类或回归预测性能 集成学习可以通过降低模型的方差 提高模型的稳定性和泛化性能 从而
  • greenDao官网

    http greenrobot org greendao documentation
  • 基于Keras实战项目-猫狗熊猫分类大战

    欢迎来到本博客 本次博客内容将继续讲解关于OpenCV的相关知识 作者简介 目前计算机研究生在读 主要研究方向是人工智能和群智能算法方向 目前熟悉深度学习 keras pytorch yolo python网页爬虫 机器学习 计算机视觉 O
  • 三个月华为od工作感受:关于转正,身份和适合谁

    三个月对Od认识的变化 关于华为Od在网上已经被讨论得很多了 在各大IT求职论坛中Od都成为流量密码了 一旦有人谈起od评论区就会开吵 这几个月中我对Od的认识也是从浅入深 对Od的态度也在变化 今年 2022年 4月份的时候那时候我刚入职
  • Redis实现商品秒杀

    随着互联网的发展和消费者的需求越来越高 商品的销售也变得越来越激烈 而对于商家来说 最直观的解决方式即为促销活动 然而 促销活动也会引发一定的风险 如果处理得不当 可能会出现 抢购 活动中的库存不足等问题 本文将利用Redis实现商品秒杀