【Redis】实现购物秒杀及分布式锁

Redis实现购物秒杀及分布式锁

全局唯一ID

Redis自增ID策略

ID构造是:时间戳 + 计数器

每天一个key,方便统计订单量

业务实现

获取指定时间的秒数

LocalDateTime timeBegin = LocalDateTime.of(2024, 1, 1, 0, 0, 0);
long second = timeBegin.toEpochSecond(ZoneOffset.UTC);

获取当前时间的秒数

long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);

全局唯一ID业务代码

public Long getID(String key) {// 获取时间戳long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);long timestamp = now - TIMESTAMP_BEGIN;// 利用redis实现自增长String date = new SimpleDateFormat("yyyyMMdd").format(new Date());Long inc = redisTemplate.opsForValue().increment("ID:" + key + ":" + date);// 拼接并返回return timestamp << 32 | inc;
}

实现秒杀下单

秒杀下单逻辑流程

业务实现

存在
不存在
充足
不足
begin
判断库存
判断存在
end
提交商品id
返回异常
扣减库存
创建订单
返回订单id
@Transactional
public String getProduct(Long id) {// 判断商品是否存在Product pro = getById(id);if (pro == null) {throw new BusinessException(400, "商品不存在");}// 判断库存int num = pro.getNum();if (num <= 0) {throw new BusinessException(400, "库存不足");}// 库存 - 1pro.setNum(num - 1);update(pro, new QueryWrapper<>());// 下订单Ordertable order = new Ordertable();order.setOrderID(idUtil.getID("order").toString());order.setUserID(123);ordertableService.save(order);return order.getOrderID();
}

“超卖”问题

问题复现

在多线程并发会产生问题

使用5000个线程进行测试

20个库存卖了210个订单

原因分析

锁的类型

超卖问题是典型的多线程安全问题,针对这一问题的常见解决方案就是加锁

悲观锁:认为线程安全问题一定会发生,因此在操作数据之前先获取锁,确保线程串行执行。

  • 例如Synchronized、Lock都属于悲观锁

乐观锁:认为线程安全问题不一定会发生,因此不加锁,只是在更新数据时去判断有没有其它线程对数据做了修改。

  • 如果没有修改则认为是安全的,自己才更新数据。
  • 如果已经被其它线程修改说明发生了安全问题,此时可以重试或异常。

乐观锁

乐观锁的关键是判断之前查询得到的数据是否有被修改过。(CAS法)

代码实现

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

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

相关文章

XCTF:warmup[WriteUP]

CtrlU查看页面源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible&q…

数据的保护:local | protected

文章目录 前言一、local二、protected总结 前言 为了数据的保护&#xff0c;我们可以通过local或者protected去修饰数据&#xff0c;本文主要记录一下它俩之间的区别。 一、local 基类中用local修饰的变量&#xff0c;在其子类中不能被访问。 如下所示&#xff0c;基类中的DO…

D2576——单片开关电压调整电路,可提供降压开关稳压器的各种功能,能驱动3A负载,有优异的电压线性度和负载调整能力。兼容型号LM2576

D2576是一块单片开关电压调整电路&#xff0c;能提供降压开关稳压器的各种功能&#xff0c;能驱动3A负载&#xff0c;有优异的电压线性度和负载调整能力。 主要特点&#xff1a; ● 3.3V. 5V和12V及可调电压输出 ● 3A输出电流 ● 外部元件少&#xff0c;仅需要四个 ● 振荡频…

【知识点】设计模式

创建型 单例模式 Singleton&#xff1a;确保一个类只有一个实例&#xff0c;并提供该实例的全局访问点 使用一个私有构造方法、一个私有静态变量以及一个公有静态方法来实现。私有构造方法确保了不能通过构造方法来创建对象实例&#xff0c;只能通过公有静态方法返回唯一的私…

无需定义 巨星登场!影驰Geforce RTX 4080 SUPER系列显卡现已发售

新春至&#xff0c;龙年到&#xff0c;电脑硬件圈可谓热闹非凡&#xff01;先是年轻小将RTX 4070 SUPER的惊艳首秀&#xff0c;再是上周首发RTX 4070TI SUPER的高性能表演~~而今&#xff0c;SUPER系列最后一位巨星已然登场&#xff01;影驰RTX 4080 SUPER系列显卡又会给我们带来…

Talk|中国科学院信息工程研究所王子泰:面向长尾学习的局部泛化分析技术

本期为TechBeat人工智能社区第568期线上Talk。 北京时间1月31日(周三)20:00&#xff0c;中国科学院信息工程研究所博士生—王子泰的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “面向长尾学习的局部泛化分析技术”&#xff0c;系统地介绍了他的团…

【深度学习:机器学习模型】如何构建您的第一个机器学习模型

【深度学习&#xff1a;机器学习模型】如何构建您的第一个机器学习模型 第 1 步&#xff1a;将您的机器学习项目置于情境中第 2 步&#xff1a;探索数据并选择机器学习算法的类型监督学习无监督学习强化学习 第 3 步&#xff1a;数据收集第 4 步&#xff1a;选择模型评估方法维…

main函数、_tmain函数和wmain函数的区别

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 今天碰到一个问题&#xff0c;算是彻底搞明白了main函数、_tmain函数和wmain函数的区别。就是使用vs2015新建一个控制台工程&#xff0c;如果入口函数是设…

【Qt学习笔记】(一)初识Qt

Qt学习笔记 1 使用Qt Creator 新建项目2 项目代码解释3 创建第一个 Hello World 程序4 关于内存泄漏问题5 Qt 中的对象树6 关于 qDebug&#xff08;&#xff09;的使用7 使用其他方式创建一个 Hello World 程序&#xff08;编辑框和按钮方式&#xff09;8 关于 Qt 中的命名规范…

Centos7配置Node环境

这里写目录标题 配置node环境变量一&#xff1a;配置前的准备工作1 创建node的下载目录2 下载node安装包3 解压 二&#xff1a;配置node环境变量: ~/.bash_profile 和 /etc/profile 的区别三&#xff1a;验证变量是否配置成功 配置node环境变量 一&#xff1a;配置前的准备工作…

网络服务综合实验项目

目录 实验要求 运行环境 基础配置 业务需求 实验步骤 一、基础配置 1.1、配置静态IP 1.1.1、 在192.168.159.130中配置 1.1.2、 在192.168.159.131中配置 ​编辑 1.2、修改主机名及hosts映射 1.2.1、在192.168.159.130中配置 1.2.2、 编辑配置hosts文件 1.2.3、重启…

录屏怎么录?看这里,方法大揭秘!

随着科技的发展&#xff0c;录制屏幕内容已经变得愈发普遍和重要。无论是为了制作教程、分享游戏技巧&#xff0c;还是进行视频会议&#xff0c;录屏都是一个不可或缺的工具&#xff0c;可是您知道录屏怎么录吗&#xff1f;本文将介绍两种录屏的方法&#xff0c;我们将分步骤详…