Java-redis实现限时在线秒杀功能

article/2025/6/7 13:27:27

1.使用redisson pom文件添加redisson

 <!--redisson--><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.23.4</version></dependency>

2.mysql数据库表设计

CREATE TABLE `order` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID',`user_id` bigint(20) NOT NULL COMMENT '用户ID',`product_id` bigint(20) NOT NULL COMMENT '商品ID',`order_no` varchar(50) NOT NULL COMMENT '订单编号',`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态(0:未支付,1:已支付,2:已取消)',`create_time` datetime NOT NULL COMMENT '创建时间',`pay_time` datetime DEFAULT NULL COMMENT '支付时间',PRIMARY KEY (`id`),UNIQUE KEY `idx_order_no` (`order_no`),KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1929810703233400835 DEFAULT CHARSET=utf8mb4 COMMENT='订单表';CREATE TABLE `product` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品ID',`name` varchar(100) NOT NULL COMMENT '商品名称',`price` decimal(10,2) NOT NULL COMMENT '商品价格',`stock` int(11) NOT NULL COMMENT '库存数量',`start_time` datetime DEFAULT NULL COMMENT '秒杀开始时间',`end_time` datetime DEFAULT NULL COMMENT '秒杀结束时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1929810179796844547 DEFAULT CHARSET=utf8mb4 COMMENT='秒杀商品表';CREATE TABLE `seckill_record` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`user_id` bigint(20) NOT NULL COMMENT '用户ID',`product_id` bigint(20) NOT NULL COMMENT '商品ID',`order_no` varchar(50) DEFAULT NULL COMMENT '订单编号',`seckill_time` datetime NOT NULL COMMENT '秒杀时间',`status` tinyint(4) NOT NULL COMMENT '状态(0:秒杀成功未支付,1:已支付,2:已取消)',PRIMARY KEY (`id`),UNIQUE KEY `idx_user_product` (`user_id`,`product_id`) COMMENT '用户商品唯一索引',KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1929810703233400836 DEFAULT CHARSET=utf8mb4 COMMENT='秒杀记录表';

3.实现逻辑

1.新增秒杀商品,添加库存数量,设置秒杀开始时间和结束时间

2.确认开始秒杀,将库存数量入redis中,避免进行超卖

3.进行秒杀

 3.1.根据商品id查询商品是否存在

 3.2.判断当前时间是否在秒杀开始时间

 3.3. 获取Redisson锁

 3.4.判断当前人是否已经秒杀过,避免重复秒杀

 3.5.判断库存是否充足,避免超卖,库存不足,返回商品已售罄

 3.6.判断库存充足,扣减库存并记录用户

 3.7.秒杀成功创建订单,返回订单号

 3.8.关闭锁,避免死锁

4.代码实现

1.秒杀控制器

@RestController
@RequestMapping("/seckill")
public class SeckillController {@Autowiredprivate SeckillService seckillService;/***  确认开始秒杀,初始化商品库存到Redis* @param product* @return*/@PostMapping("/initStock")public AjaxResult initStock(@RequestBody Product product) {return seckillService.initStock(product);}/*** 开始秒杀* @return*/@PostMapping("/start")public AjaxResult startSeckill(Long userId, Long productId) {return seckillService.startSeckill(userId,productId);}}

2.秒杀实现类

package com.thk.service.impl;import com.thk.domain.Order;
import com.thk.domain.Product;
import com.thk.domain.SeckillRecord;
import com.thk.mapper.OrderMapper;
import com.thk.mapper.ProductMapper;
import com.thk.mapper.SeckillRecordMapper;
import com.thk.service.SeckillService;
import com.thk.utils.AjaxResult;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class SeckillServiceImpl implements SeckillService {@Autowiredprivate ProductMapper productMapper;@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate SeckillRecordMapper seckillRecordMapper;@Autowiredprivate RedissonClient redissonClient;// 商品库存key前缀private static final String STOCK_PREFIX = "seckill:stock:";// 秒杀用户集合key前缀(用于防止重复秒杀)private static final String USER_SET_PREFIX = "seckill:users:";// 分布式锁key前缀private static final String LOCK_PREFIX = "seckill:lock:";/*** 确认开始秒杀,初始化商品库存到Redis** @param product* @return*/@Override@Transactional(rollbackFor = Exception.class)public AjaxResult initStock(Product product) {Product product1 = productMapper.selectById(product.getId());if (product1 != null) {String stockKey = STOCK_PREFIX + product1.getId();RAtomicLong atomicLong = redissonClient.getAtomicLong( stockKey );atomicLong.set(product1.getStock());// 设置过期时间(秒)long expireSeconds = (product1.getEndTime().getTime() - System.currentTimeMillis()) / 1000;boolean expireResult = atomicLong.expire(expireSeconds, TimeUnit.SECONDS);return AjaxResult.success(expireResult);}return AjaxResult.error("商品不存在");}/*** 开始秒杀** @return*/@Override@Transactional(rollbackFor = Exception.class)public AjaxResult startSeckill(Long userId, Long productId) {// 1. 验证秒杀时间Product product = productMapper.selectById(productId);if (product == null) return AjaxResult.error("商品不存在");long now = System.currentTimeMillis();if (now < product.getStartTime().getTime()) {return AjaxResult.error("秒杀未开始");}if (now > product.getEndTime().getTime()) {return AjaxResult.error("秒杀已结束");}// 2. 获取Redisson分布式锁String lockKey = LOCK_PREFIX + productId;RLock lock = redissonClient.getLock(lockKey);try {boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);if (!locked) return AjaxResult.error("系统繁忙,请稍后再试");// 3. 使用Redisson的RSet检查重复秒杀String userKey = USER_SET_PREFIX + productId;RSet<String> userSet = redissonClient.getSet(userKey);if (userSet.contains(userId.toString())) {return AjaxResult.error("不能重复秒杀");}// 4. 使用Redisson的RAtomicLong检查库存String stockKey = STOCK_PREFIX + productId;RAtomicLong atomicStock = redissonClient.getAtomicLong(stockKey);if (atomicStock.get() <= 0) {return AjaxResult.error("商品已售罄");}// 5. 扣减库存并记录用户atomicStock.decrementAndGet();userSet.add(userId.toString());// 6. 创建订单String orderNo = generateOrderNo();createOrder(userId, productId, orderNo);return AjaxResult.success(orderNo);} catch (InterruptedException e) {Thread.currentThread().interrupt();return AjaxResult.error("系统异常");} finally {if (lock.isLocked() && lock.isHeldByCurrentThread()) {//关闭锁lock.unlock();}}}private void createOrder(Long userId, Long productId, String orderNo) {Order order = new Order();order.setUserId( userId );order.setProductId( productId );order.setOrderNo( orderNo );order.setStatus( 0 );order.setCreateTime( new Date() );orderMapper.insert( order );SeckillRecord record = new SeckillRecord();record.setUserId( userId );record.setProductId( productId );record.setOrderNo( orderNo );record.setSeckillTime( new Date() );record.setStatus( 0 );seckillRecordMapper.insert( record );}private String generateOrderNo() {return "O" + System.currentTimeMillis();}
}

5.测试

1.添加秒杀商品,设置库存,开始时间,结束时间

2.确认开始,将库存存入redis中

redis查看库存是否存在

3.开始秒杀,输入用户id和商品编号进行秒杀

秒杀成功,创建订单,新增商品秒杀记录,返回订单号,redis库存减少,redis新增用户秒杀记录

订单记录

秒杀记录

redis库存

redis新增用户秒杀记录

4.重复秒杀

5.避免超卖

6.秒杀结束,超时秒杀结束


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

相关文章

龙虎榜——20250603

上证指数放量收阳线&#xff0c;阳包阴&#xff0c;量能超过5天均量&#xff0c;个股涨多跌少&#xff0c;行情有所回暖。 深证指数缩量收阳线&#xff0c;再次回打支撑位。 2025年6月3日龙虎榜行业方向分析 1. 医药&#xff08;创新药原料药出口&#xff09; 代表标的&…

永磁同步电机无速度算法--互补滑模观测器

一、原理介绍 采用了互补滑模变结构观测器&#xff0c;滑模面选择了广义滑模面和互补滑模面相结合的设计&#xff0c;这样可以有效地降低系统的跟踪误差&#xff0c;提高系统的跟踪性能&#xff0c;切换控制率选择饱和函数&#xff0c;抑制了传统SMC 的抖振现象。 二、仿真模型…

2025年AIR SCI1区TOP,多策略增强蜣螂算法MDBO+实际工程问题,深度解析+性能实测

目录 1.摘要2.蜣螂优化算法DBO原理3.改进策略4.结果展示5.参考文献6.代码获取7..算法辅导应用定制读者交流 1.摘要 蜣螂优化算法&#xff08;DBO&#xff09;作为一种创新元启发式算法&#xff0c;虽具备良好的数值优化能力&#xff0c;但存在收敛速度慢且易陷入局部最优的问题…

【notepad++】如何设置notepad++背景颜色?

如何设置notepad背景颜色&#xff1f; 设置--语言格式设置 勾选使用全局背景色 例如选择护眼色---80&#xff0c;97&#xff0c;205&#xff1b;

Gitee Wiki:重塑关键领域软件研发的知识管理范式

在数字化转型浪潮席卷全球的当下&#xff0c;关键领域软件研发正面临前所未有的知识管理挑战。传统文档管理模式的局限性日益凸显&#xff0c;知识传承的断层问题愈发严重&#xff0c;团队协作效率的瓶颈亟待突破。Gitee Wiki作为新一代知识管理平台&#xff0c;正在通过技术创…

电源防反接保护电路分析

电路&#xff1a; 这是一个电源输入防反接的电路&#xff0c;通过NMOS来实现。 1、正常接入电源。 正常接入电源的时候&#xff0c;VCC12V&#xff0c;这时候&#xff0c;电流通过R1、R2和NMOS的体二极管D形成一个回路&#xff0c;此时NMOS还未导通。 通过计算可以得到Vs0.7V&a…

焊缝缺陷焊接缺陷识别分割数据集labelme格式5543张4类别

数据集中有超过一半为增强图片&#xff0c;请认真观察图片预览 数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;5543 标注数量(json文件个数)&#xff1a;5543 标注类别数&#xff1a;4…

腾讯云国际版和国内版账户通用吗?一样吗?为什么?

在当今全球化的数字化时代&#xff0c;云计算服务成为众多企业和个人拓展业务、存储数据的重要选择。腾讯云作为国内领先的云服务提供商&#xff0c;其国际版和国内版备受关注。那么&#xff0c;腾讯云国际版和国内版账户是否通用&#xff1f;它们究竟一样吗&#xff1f;背后又…

C++初赛的三讲

C++初赛的三讲 C++初赛第一/二讲链接:CSP-J算法串讲完善程序解题思路1.查找算法顺序查找二分查找二分查找的步骤二分查找法的代码2.排序算法冒泡排序冒泡排序的代码插入排序插入排序的代码选择排序选择排序的代码计数排序C++初赛第一/二讲链接: 1.链接: C++初赛第一讲1.0 2.…

pikachu靶场通关笔记12 XSS关卡08-XSS之htmlspecialchars(四种方法渗透)

目录 一、htmlspecialchars 二、源码分析 1、进入靶场 2、代码审计 3、渗透思路 &#xff08;1&#xff09;利用单引号绕过 &#xff08;2&#xff09;利用协议绕过 三、渗透实战 1、探测是否有过滤 2、注入payload1 3、注入payload2 4、注入payload3 5、注入payl…

Github 2025-06-03Python开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2025-06-03统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目10Rust项目1HTML项目1C项目1 系统设计指南 创建周期&#xff1a;2507 天开发语言&#xff1a;Pyt…

多线程环境中,如果多个线程同时尝试向同一个TCP客户端发送数据,添加同步机制

原代码 public async Task SendToClientAsync(TcpClient targetClient, byte[] data, int offset, int length) {try{// 1. 检查客户端是否有效if (targetClient null || !targetClient.Connected){Console.WriteLine("Cannot send: client is not connected");ret…

java后端生成心电图-jfreechart

用jfreechart生成心电图 先上成功的图片 上代码 1.导入包 implementation org.jfree:jfreechart:1.5.4implementation org.jfree:jcommon:1.0.242.实现代码 对数据进行滤波 转换单位 package com.shinrun.infrastructure.util;import java.util.ArrayList; import java.ut…

项目前置知识——不定参以及设计模式

1.C语言不定参宏函数 c语言中&#xff0c;printf就是一个不定参函数&#xff0c;在使用不定参宏函数时&#xff0c;我们使用__VA_ARGS__来解析不定参&#xff1a; #include <iostream> #include <cstdarg>#define LOG(fmt/*格式*/, .../*用...表示不定参*/) prin…

redis哨兵与集群部署

目录 一.哨兵模式部署 1.设置Redis哨兵模式配置文件的属组以及属主&#xff08;所有节点操作&#xff09; 2.修改Redis哨兵模式的配置文件&#xff08;所有节点操作&#xff09; 3.准备server文件启动&#xff0c;先启主再启从&#xff08;所有节点操作&#xff09; 4.验证…

飞腾D2000,麒麟系统V10,docker,ubuntu1804,小白入门喂饭级教程

#下载docker Index of linux/static/stable/ 根据电脑的CPU类型选择&#xff1a; Intel和AMD选x86_64飞腾D2000选aarch64 #选择较新的版本 #在包含下载的docker-XX.X.X.tgz的文件夹中右键->打开终端 # 解压安装包&#xff08;根据实际下载的文件&#xff09; tar -zxvf …

torch.nn中的各种组件

Content 线性层 (Linear Layers)**核心原理&#xff1a;线性变换****关键组件****示例代码****示例1&#xff1a;基础线性层 (nn.Linear)****示例2&#xff1a;双线性层 (nn.Bilinear)** **应用场景** 非线性激活函数 (Non-linear Activations)**常用非线性激活函数****1. ReLU…

高性能分布式消息队列系统(二)

上一篇博客将C进行实现消息队列的用到的核心技术以及环境配置进行了详细的说明&#xff0c;这一篇博客进行记录消息队列进行实现的核心模块的设计 五、项目的需求分析 5.1、项目框架的概念性理解 5.1.1、消息队列的设计和生产消费者模型的关系 在现代系统架构中&#xff0c;…

AI健康小屋+微高压氧舱:科技如何重构我们的健康防线?

目前&#xff0c;随着科技和社会的不断发展&#xff0c;人们的生活水平和方式有了翻天覆地的变化。 从吃饱穿暖到吃好喝好再到健康生活&#xff0c;观念也在逐渐发生改变。 尤其是在21世纪&#xff0c;大家对健康越来越重视&#xff0c;这就不得不提AI健康小屋和氧舱。 一、A…

Azure DevOps Server 2022.2 补丁(Patch 5)

微软Azure DevOps Server的产品组在4月8日发布了2022.2 的第5个补丁。下载路径为&#xff1a;https://aka.ms/devops2022.2patch5 这个补丁的主要功能是修改了代理(Agent)二进制安装文件的下载路径&#xff1b;之前&#xff0c;微软使用这个CND(域名为vstsagentpackage.azuree…