Redis的应用场景及类型
目录
一、Redis的应用场景
1、限流
2、分布式锁
3、点赞
4、消息队列
二、Redis类型的命令及用法
1、String类型
2、Hash类型
3、List类型
4、Set类型
5、Zset类型
6、Redis工具类
Redis使用缓存的目的就是提升读写性能
实际业务场景下,我们就可以把 Mysql 中的热点数据缓 存到 Redis 中,提升读取性能,同时也减轻了 Mysql 的读取压力
一、Redis的应用场景
Redis除了做缓存以外,还可以用
- 限流
- 分布式锁
- 点赞/排行榜
- 消息队列
还有其他场景:计数器、互关好友、购物车和商品标签等等
1、限流
利用Redis的过期键和计数器功能,实现API的限流功能,防止服务被滥用
方法一:记录IP在某个时间段访问某接口的次数
使用IP作为Key和其他信息作为Key,访问次数作为Value,访问一次Incr增加一次,超过规定次数则返回false
但问题是:限流时间段是固定的
比如:某接口在1分钟内请求次数不超过1000次

就是00:59分,用户已经访问了999次,1:00key值过期,1:01又访问了999次
看起来好像是没问题,但是00:59—1:01的仅2s时间段内,接口被访问了1000+999次,明显错误
方法二:滑动窗口
为了避免方法一种由于key过期导致短期内访问量增大的情况,将时间改成动态的
在每次接口访问时,记录当前访问的时间点,并计算前1min内用户访问该接口的总次数,如果总次数大于1000次,则不允许用户访问该接口

以上两种利用redis实现限流的方式基本能满足我们大部分的业务需要,对于部分要求限流粒度更高更准的业务,可以引入Sentinel来满足业务需要
2、分布式锁
为什么使用分布式锁?
在单机部署的时候,可以使用 Java 中提供的 JUC 锁机制避免多线程同时操作一个共享变量产生的安全问题,通过锁(synchronzied 或 lock)来锁住自己的线程资源,从而防止缓存击穿
Redis的缓存问题:缓存穿透、缓存击穿和缓存雪崩-CSDN博客
这是一种本地加锁的方式,在分布式情况下会带来数据不一致的问题
比如:服务 A 获取数据后,更新缓存 key =100,服务 B 不受服务 A 的锁限制,并发去更新缓存 key = 99,最后的结果可能是 99 或 100,但这是一种未知的状态,与期望结果不一致
①基础版
Redis的SET命令有一个NX参数,可以实现「key不存在才插入」,因此可以用它来实现分布式锁:
SetNX(key,value)
redisTemplate.opsForValue().setIfAbsent(“k”, “v”)
也就是
SET lockKey requestId NX PX expireTime
-
lockKey表示锁的资源, -
requestId 全局唯一的业务id,避免存在加锁和释放锁乱掉的情况
-
NX:表示只有lockKey不存在的时候才能SET成功,从而保证只有一个客户端可以获得锁。 -
PX expireTime设置锁的超时时间,单位是毫秒;也可以使用EX seconds以秒为单位设置超时时间
伪代码:
try {if (jedis.set(lockKey, requestId, "NX", "PX", expireTime))) {//业务处理return true;}
} finally{//判断是不是当前线程加的锁,是才释放if(requestd.equals.(jedis.get(lockKey))){//释放锁unlock(lockKey,requestId);}
}
return false;
②Redisson实现
Redisson 是 Redis 的 Java 客户端之一,支持原子性加/解锁、锁重试、可重入锁、RedLock 等功能
// 获取分布式锁
RLock lock = redissonClient.getLock("myLock");
try {// 尝试加锁,最多等待 10 秒,加锁后的锁有效期为 30 秒boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);if (locked) {// 成功获取锁,执行业务逻辑System.out.println("获取锁成功,执行业务逻辑...");} else {// 获取锁失败,可能是超时等待或者其他原因System.out.println("获取锁失败...");}
} catch (InterruptedException e) {e.printStackTrace();
} finally {// 释放锁lock.unlock();// 关闭 Redisson 客户端redissonClient.shutdown();
}
Redisson存储分布式锁是通过Hash结构进行存储的,内置的键值对是< 线程标识,重入次数>,其中重入次数便可用于实现可重入机制
3、点赞
点赞就需要用到Redis的Set类型,Set类型是Redis中的一个无序集合,它可以存储一组字符串元素,并且每个元素都是唯一的
【点赞】SADD key member:向集合中添加一个或多个元素
redisTemplate.opsForSet().add(key, values)
【取消点赞】SREM key:删除元素
redisTemplate.opsForSet().remove(key,value)
【点赞的所有用户】SMEMBERS key:返回集合中的所有元素
redisTemplate.opsForSet().members(key)
【是否点赞】SISMEMBER key member:判断元素是否在集合中
redisTemplate.opsForSet().isMember(key, value)
【点赞数】scard(key):元素长度
redisTemplate.opsForSet().size(key)
场景:对活动的相册图片进行点赞且对点赞数量进行计数的功能
public void like(Long activityId) {LzmUserInfo userInfo = UserContextHolder.getLzmUserInfo();String key = ACTIVITY.ACTIVITY_LIKE_KEY + activityId;Boolean member = stringRedisTemplate.opsForSet().isMember(key, userInfo.getUserId().toString());if (BooleanUtil.isFalse(member)) {//未点赞,点赞数+1this.update(Wrappers.<ActivityManageEntity>lambdaUpdate().setSql("like_num = like_num + 1").eq(ActivityManageEntity::getActivityId, activityId).eq(ActivityManageEntity::getIsDelete, IsDeleteEnum.NORMAL.getCode()));redisTemplate.opsForSet().add(key, userInfo.getUserId().toString());} else {//取消点赞,点赞数-1this.update(Wrappers.<ActivityManageEntity>lambdaUpdate().setSql("like_num = like_num - 1").gt(ActivityManageEntity::getLikeNum, 0).eq(ActivityManageEntity::getActivityId, activityId).eq(ActivityManageEntity::getIsDelete, IsDeleteEnum.NORMAL.getCode()));redisTemplate.opsForSet().remove(key, userInfo.getUserId().toString());}}
4、消息队列
Redis可以实现简单的队列。在生产者端,使用LPUSH加入到某个列表中;在消费端,不断的使用RPOP指令取出这些数据,或者使用阻塞的BRPOP指令获取数据,用于处理异步任务,例如邮件发送、后台任务处理,小规模的抢购需求等
场景:邮件发送
生产者发布消息
LPUSH queue msg1
消费者 拉取消息
RPOP queue

二、Redis类型的命令及用法
1、String类型
| 操作 | 命令 | 用法 |
|---|---|---|
| 设置 | set(“k”,“v”) | template.opsForValue().set(“k”,“v”) |
| 获取 | get(“k”) | template.opsForValue().get(“k”) |
| 增1 | incr(“k”) | template.boundValueOps(“k”).increment(1) |
| 减1 | decr(“k”) | template.boundValueOps(“k”).increment(-1) |
| 设置时效 | setex(“k”,seconds,“v”) | template.opsForValue().set(“k”,“v”,20, TimeUnit.SECONDS) |
| key不存在就设置 | setnx(“k”,“v”) | template.opsForValue().setIfAbsent(“k”, “v”) |
| 获取key过期时间 | ttl(“k”) | template.getExpire(“k”) |
| 删除 | del(“k”) | template.delete(“k”) |
2、Hash类型
| 操作 | 命令 | 用法 |
|---|---|---|
| 设置 | hset(“k1”,“k2”,“k3”) | template.opsForHash().put(“k1”,“k2”,“k3”) |
| 获取 | hget(“k1”,“k2”) | template.opsForHash().get(“k1”,“k2”) /template.opsForHash().values(“k1”) |
| 删除 | hdel(“k1”,“k2”) | template.opsForHash().delete(“k1”,“k2”) |
| 是否存在 | hexists(“k1”,“k2”) | template.opsForHash().hasKey(“k1”,“k2”) |
3、List类型
| 操作 | 命令 | 用法 |
|---|---|---|
| 从右侧添加 | rpush(“k”,“v”) | template.opsForList().rightPush(“k”,“v”) |
| 从右侧移除 | rpop(“list”) | template.opsForList().rightPop(“k”) |
| 长度 | llen(“k”) | template.opsForList().size(“k”) |
| 获取指定范围的元素 | lrange(“list”,0,-1) -1指全部 | template.opsForList().range(“list”, 0, -1) |
4、Set类型
| 操作 | 命令 | 用法 |
|---|---|---|
| 添加 | sadd(“k”,“v”) | template.opsForSet().add(“k”,“v”) |
| 值移除 | srem(“k”,“v”) | template.opsForSet().remove(“k”,“v”) |
| 直接移除 | spop(“k”) | template.opsForSet().pop(“k”) |
| 获取所有 | smembers("k") | template.opsForSet().members("k") |
| 是否存在 | sismember("k") | emplate.opsForSet().isMember("k","v") |
| 长度 | scard(“k”) | template.opsForSet().size(“k”) |
| 交集 | sinter(“k1”,“k2” ) | template.opsForSet().intersect(“k1”, “k2”) |
| 并集 | sunion(“k1”,“k2” ) | template.opsForSet().union(“k1”, “k2”) |
| 差集 | sdiff(“k1”,“k2” ) | template.opsForSet().difference(“k1”, “k2”) |
5、Zset类型
| 操作 | 命令 | 用法 |
|---|---|---|
| 增加 | zadd(“k”,1,“a”) | template.opsForZSet().add(“k”,“1”,a) |
| 排名结果 | zrevrange(“k”, 0, -1) | template.opsForZSet().reverseRange(“k”, 0, -1) |
| 排名分数 | zrevrangeByScoreWithScores(“k”, 1, 10); | template.opsForZSet().reverseRangeByScore(“k”, 1, 100) |
| 修改分数 | zincrby(“k”,20,“a”) | template.opsForZSet().incrementScore(“k”,“20”,a) |
| 数量 | zcard(“k”) | template.opsForZSet().zCard(“k”) |
| 获取排名 | zrank(“k”,“a”) | template.opsForZSet().rank(“k”,“a”) |
6、Redis工具类
@Component
public class RedisUtils {@Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 添加数据*/public void set(String key, Object value) {redisTemplate.opsForValue().set(key, value);}/*** 如果key不存在,则设置key的值为value并返回true,否则返回false*/public boolean setNx(String key, String value) {return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value));}/*** 如果key不存在,则设置key的值为value以及过期时间,并返回true,否则返回false,*/public boolean setNx(String key, String value, long timeout, TimeUnit unit) {return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));}/*** 根据key获取数据*/public Object get(String key) {return redisTemplate.opsForValue().get(key);}/*** 根据key删除数据*/public void delete(String key) {redisTemplate.delete(key);}/*** 向集合中添加一个或多个元素*/public void add(String key, Object... values) {redisTemplate.opsForSet().add(key, values);}/*** 将 value 插入到 key 对应的列表的头部*/public void leftPush(String key, Object value) {//。redisTemplate.opsForList().leftPush(key, value);}/*** 将 value 插入到 key 对应的列表的尾部*/public void rightPush(String key, Object value) {redisTemplate.opsForList().rightPush(key, value);}/*** 从 key 对应的列表的头部删除并返回一个元素*/public Object leftPop(String key) {return redisTemplate.opsForList().leftPop(key);}/*** 从 key 对应的列表的尾部删除并返回一个元素*/public Object rightPop(String key) {return redisTemplate.opsForList().rightPop(key);}/*** 返回列表中指定范围内的元素*/public List<Object> range(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}/*** 返回集合中的所有元素*/public Set<Object> members(String key) {return redisTemplate.opsForSet().members(key);}/*** 判断元素是否在集合中*/public Boolean isMember(String key, Object value) {return redisTemplate.opsForSet().isMember(key, value);}/*** 向有序集合中添加一个元素并指定分数*/public void add(String key, double score, Object value) {redisTemplate.opsForZSet().add(key, value, score);}/*** 获取指定score范围内元素*/public Set<ZSetOperations.TypedTuple<Object>> rangeWithScores(String key, long start, long end) {return redisTemplate.opsForZSet().rangeWithScores(key, start, end);}
}
相关文章:
Redis的应用场景及类型
目录 一、Redis的应用场景 1、限流 2、分布式锁 3、点赞 4、消息队列 二、Redis类型的命令及用法 1、String类型 2、Hash类型 3、List类型 4、Set类型 5、Zset类型 6、Redis工具类 Redis使用缓存的目的就是提升读写性能 实际业务场景下,我们就可以把 Mys…...
【图像处理】不智能的目标识别
目录 目标识别的划分 识别入门 概念学习 滤波 模版 阈值化 形态学操作 开运算 闭运算 编程语言 示例 大家有没有想过在没有人工智能或者说没有机器学习的的时候,计算机是怎么做目标识别的? 计算机视觉时至今日也是急需人才的领域&…...
《500 Lines or Less》(5)异步爬虫
https://aosabook.org/en/500L/a-web-crawler-with-asyncio-coroutines.html ——A. Jesse Jiryu Davis and Guido van Rossum 介绍 网络程序消耗的不是计算资源,而是打开许多缓慢的连接,解决此问题的现代方法是异步IO。 本章介绍一个简单的网络爬虫&a…...
Transformer!自注意力机制的高层级理解Attention Is All You Need!
背景 最近在不断深入学习LLM的相关内容,那么transformer就是一个绕不开的话题。然而对于一个NLP门外汉来说,论文看得是真头疼,总览全网,我们似乎缺少一个至高而下的高层级理解。所以本文就来弥补此方面的缺失~ 本文并不讲解有关…...
关于使用Postman在请求https网址没有响应,但是用浏览器有响应的问题解决
一、问题描述 使用postman调用正式环境的公共接口,无需鉴权,但是产生了返回状态码200,但是data中却无数据,如下 {"code": "200","message": "操作成功","data": {"qr_c…...
【React 】开发环境搭建详细指南
文章目录 一、准备工作1. 安装 Node.js 和 npm2. 选择代码编辑器 二、创建 React 项目1. 使用 Create React App2. 手动配置 React 项目 三、集成开发工具1. ESLint 和 Prettier2. 使用 Git 进行版本控制 在现代前端开发中,React 是一个非常流行的框架,用…...
结构体笔记
结构体 C语言中的数据类型: 基本数据类型:char/int/short/double/float/long 构造数据类型:数组,指针,结构体,共用体,枚举 概念: 结构体是用户自定义的一种数据类型,…...
Elasticsearch:Golang ECS 日志记录 - zerolog
ECS 记录器是你最喜欢的日志库的格式化程序/编码器插件。它们可让你轻松地将日志格式化为与 ECS 兼容的 JSON。在本教程中,我将详述如何 编码器以 JSON 格式记录日志,并以 ECS 错误格式处理错误字段的记录。 默认情况下,会添加以下字段&…...
Ip2region - 基于xdb离线库的Java IP查询工具提供给脚本调用
文章目录 Pre效果实现git clone编译测试程序将ip2region.xdb放到指定目录使用改进最终效果 Pre OpenSource - Ip2region 离线IP地址定位库和IP定位数据管理框架 Ip2region - xdb java 查询客户端实现 效果 最终效果 实现 git clone git clone https://github.com/lionsou…...
研发管理革命:探索顶尖的工时系统选择
国内外主流的10款研发工时管理系统对比:PingCode、Worktile、无鱼项目工时系统、Toggl Track、泽众ALM、Asana、Jira、GitHub、Trello、TrackingTime。 在研发团队中,工时管理常常成为效率瓶颈,尤其是在资源分配和项目进度跟踪方面。选择合适…...
微服务-MybatisPlus下
微服务-MybatisPlus下 文章目录 微服务-MybatisPlus下1 MybatisPlus扩展功能1.1 代码生成1.2 静态工具1.3 逻辑删除1.4 枚举处理器1.5 JSON处理器**1.5.1.定义实体****1.5.2.使用类型处理器** **1.6 配置加密(选学)**1.6.1.生成秘钥**1.6.2.修改配置****…...
【python_将一个列表中的几个字典改成二维列表,并删除不需要的列】
def 将一个列表中的几个字典改成二维列表(original_list,headersToRemove_list):# 初始化一个列表用于存储遇到的键,保持顺序ordered_keys []# 遍历data中的每个字典,添加其键到ordered_keys,如果该键还未被添加for d in original_list:for …...
IDEA的pom.xml显示ignored 的解决办法
问题: idea中创建Maven module时,pom.xml出现ignored。 原因: 相同名称的module在之前被创建删除过,IDEA会误以为新的同名文件是之前删除掉的,将这个新的module的pom.xml文件忽略掉显示ignored. 解决: 在…...
2. 卷积神经网络无法绕开的神——LeNet
卷积神经网络无法绕开的大神——LeNet 1. 基本架构2. LeNet 53. LeNet 5 代码 1. 基本架构 特征抽取模块可学习的分类器模块 2. LeNet 5 LeNet 5: 5 表示的是5个核心层,2个卷积层,3个全连接层.核心权重层:卷积层、全连接层、循环层ÿ…...
【区块链】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能
审核看清楚了 ! 这是以太坊测试网络!用于学习的测试网络!!! 有关web3 和区块链的内容为什么要给我审核不通过? 别人凭什么可以发! 目标成果: 实现功能分析: 显示账户信…...
关于珞石机器人二次开发SDK的posture函数的算法RX RY RZ纠正 C#
在珞石SDK二次开发的函数钟,获取当前机器人位姿的函数posture函数在输出时会发现数据不正确,与示教器数据不一致。 其中第一个数据正确 第二三各数据为相反 第四五六各数据为弧度制 转换方法为(弧度/PI)*180度 然后发现第四个数据还要加上180度 第五…...
【Three.js基础学习】17.imported-models
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 课程回顾: 如何在three.js 中引入不同的模型? 1. 格式 (不同的格式) https://en.wikipedia.org/wiki/List_of_file_form…...
Spring Bean - xml 配置文件创建对象
类型: 1、值类型 2、null (标签) 3、特殊符号 (< -> < ) 4、CDATA <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/bea…...
uniapp map组件自定义markers标记点
需求是根据后端返回数据在地图上显示标记点,并且根据数据状态控制标记点颜色,标记点背景通过两张图片实现控制 <mapstyle"width: 100vw; height: 100vh;":markers"markers":longitude"locaInfo.longitude":latitude&…...
Windows:批处理脚本学习
目录 一、第一个批处理文件 1. &&和 | | 2. | 和 & 二、变量 1.传参变量%name 2.初始化变量set命令 3.变量的使用 4.局部变量与全局变量 5.使用环境变量 6.扩充变量语法 三、注释REM和 :: 四:函数 1.定义函数 2.…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
