Redis 五大基本数据类型及其应用场景进阶(缓存预热、雪崩 、穿透 、击穿)

Redis 数据类型及其应用场景

Redis 是什么?

Redis是一个使用C语言编写的高性能的基于内存的非关系型数据库,基于Key/Value结构存储数据,通常用来 缓解高并发场景下对某一资源的频繁请求 ,减轻数据库的压力。它支持多种数据类型,如字符串、哈希、列表、集合、有序集合等。Redis以其高性能、高可靠性和丰富的特性而闻名,被广泛应用于缓存、消息队列、实时分析等领域。

Redis 的优势

  1. 高性能:Redis的所有数据都存储在内存中,支持每秒处理上百万的读写操作。
  2. 丰富的数据类型:Redis支持多种数据类型,可以灵活地满足不同的业务需求。
  3. 原子性操作:Redis提供了许多原子性操作,如INCR、DECR、RPOP等,可以避免并发问题。
  4. 持久化:Redis支持RDB和AOF两种持久化方式,可以保证数据的安全性。

Redis 数据类型详解以及应用场景

具体的业务场景下的代码参考(点这里噢🌹🌹🌹)

Redis数据类型简单描述结合Java理解
StringValue 是String类型Map<String,String> JSON
SetValue 是Set类型Map套SetSet放的是不重复的valueMap<String,Set>
ZsetValue 是Set类型Map套SetSet放的是不重复的value能排序Map<String,TreeSet>
ListMap套ListList可以重复的value Index 下标Map<String,List>
HashMap套MapMap<String,Map<String,Object>>

1. String(字符串)

String是Redis最基本的数据类型,它可以存储任何形式的字符串,包括二进制数据。在Redis中,String类型的值最大可以达到512MB。

String的常用命令
  • SET:设置一个键值对
  • GET:获取一个键对应的值
  • INCR:对一个整数类型的键进行自增操作
  • DECR:对一个整数类型的键进行自减操作
  • SETEX:设置一个键值对,同时指定过期时间
String的应用场景
  1. 缓存:String类型可以用于缓存用户信息、商品详情等常用数据,提高系统的查询效率。
// 将用户信息缓存到Redis中
String userId = "1001";
String userInfo = "{\"id\":\"1001\",\"name\":\"Tom\",\"age\":25}";
jedis.set("user:" + userId, userInfo);// 从Redis中获取用户信息
String cachedUserInfo = jedis.get("user:" + userId);
  1. 计数器:利用INCR、DECR等命令,可以实现计数器功能,如统计网站的访问量、文章的点赞数等。
// 文章点赞数+1
String articleId = "1001";
jedis.incr("article:" + articleId + ":likes");// 获取文章点赞数
String likesStr = jedis.get("article:" + articleId + ":likes");
int likes = Integer.parseInt(likesStr);
  1. 分布式锁:利用SET命令的NX选项(只在键不存在时才设置值)和EX选项(设置过期时间),可以实现简单的分布式锁功能。
String lockKey = "lock:1001";
String lockValue = UUID.randomUUID().toString();// 获取锁,过期时间30秒
String result = jedis.set(lockKey, lockValue, "NX", "EX", 30);if ("OK".equals(result)) {// 获取锁成功,执行业务逻辑// ...// 释放锁if (lockValue.equals(jedis.get(lockKey))) {jedis.del(lockKey);}
} else {// 获取锁失败,处理异常情况// ...
}

2. List(列表)

Redis的List类型是一个双向链表,支持从头部或尾部进行插入和删除操作。一个List类型的键可以存储多个字符串值。

List的常用命令
  • LPUSH:从列表左端插入一个或多个值
  • RPUSH:从列表右端插入一个或多个值
  • LPOP:移除并返回列表左端的第一个元素
  • RPOP:移除并返回列表右端的第一个元素
  • LRANGE:获取列表在给定范围上的所有值
List的应用场景
  1. 消息队列:List类型可以用作简单的消息队列,生产者使用LPUSH命令插入消息,消费者使用RPOP命令获取消息。
// 生产者代码
String taskQueue = "queue:tasks";
String task = "...";
jedis.lpush(taskQueue, task);// 消费者代码
String taskQueue = "queue:tasks";
String task = jedis.rpop(taskQueue);
if (task != null) {// 处理任务// ...
}
  1. 最新列表:使用LPUSH命令可以将最新的数据插入到列表头部,使用LTRIM命令可以限制列表的长度,实现最新N个元素的列表。
String latestNewsKey = "latest:news";
String news = "...";// 将最新新闻插入到列表头部
jedis.lpush(latestNewsKey, news);// 只保留最新的100条新闻
jedis.ltrim(latestNewsKey, 0, 99);// 获取最新的10条新闻
List<String> latestNews = jedis.lrange(latestNewsKey, 0, 9);

3. Set(集合)

Redis的Set类型是一个无序且不重复的字符串集合。可以对Set执行交集、并集、差集等操作。

Set的常用命令
  • SADD:向集合中添加一个或多个成员
  • SMEMBERS:返回集合中的所有成员
  • SISMEMBER:判断成员是否存在于集合中
  • SINTER:返回给定所有集合的交集
  • SUNION:返回给定所有集合的并集
  • SDIFF:返回给定所有集合的差集
Set的应用场景
  1. 标签系统:Set类型可以用于实现标签功能,一个用户可以对应多个标签,多个用户也可以对应同一个标签。
String user1Tags = "user:1001:tags";
String user2Tags = "user:1002:tags";// 给用户添加标签
jedis.sadd(user1Tags, "music", "travel");
jedis.sadd(user2Tags, "music", "sports");// 获取用户共同感兴趣的标签
Set<String> commonTags = jedis.sinter(user1Tags, user2Tags);
  1. 抽奖活动:Set类型可以用于实现抽奖功能,将所有参与用户加入到一个Set中,然后随机抽取若干个用户作为中奖者。
String lotteryKey = "lottery:users";// 将用户加入抽奖活动
jedis.sadd(lotteryKey, "user:1001", "user:1002", "user:1003");// 随机抽取2名中奖者
List<String> winners = jedis.srandmember(lotteryKey, 2);

4. Zset(有序集合)

Zset类型(Sorted Set)是一个有序的,不重复的字符串集合。与Set类型不同,Zset中的每个成员都关联了一个评分(score),评分用于对成员进行排序。

Zset的常用命令
  • ZADD:向有序集合中添加一个或多个成员,或者更新已存在成员的评分
  • ZRANGE:返回有序集合中,指定区间内的成员,成员按评分值递增排序
  • ZREVRANGE:返回有序集合中,指定区间内的成员,成员按评分值递减排序
  • ZRANGEBYSCORE:返回有序集合中,所有评分介于min和max之间(包括等于min或max)的成员
  • ZRANK:返回有序集合中指定成员的排名
Zset的应用场景
  1. 排行榜:Zset类型可以用于实现各种排行榜功能,如商品销量排行、游戏玩家积分排名等。
String rankingKey = "sales:ranking";// 添加商品销量数据
jedis.zadd(rankingKey, 100, "product:1001");
jedis.zadd(rankingKey, 80, "product:1002");
jedis.zadd(rankingKey, 120, "product:1003");// 获取销量前3名的商品
Set<String> topProducts = jedis.zrevrange(rankingKey, 0, 2);
  1. 延时队列:利用Zset的评分值代表任务的执行时间,可以实现延时队列的功能。
String delayQueueKey = "delay:queue";// 添加延时任务
long now = System.currentTimeMillis();
jedis.zadd(delayQueueKey, now + 60000, "task:1"); // 1分钟后执行
jedis.zadd(delayQueueKey, now + 300000, "task:2"); // 5分钟后执行// 获取当前需要执行的任务
Set<String> tasks = jedis.zrangeByScore(delayQueueKey, 0, now);

5. Hash(哈希)

Redis的Hash类型可以看作是一个字符串字段(field)和字符串值(value)的映射表,特别适合用于存储对象。每个哈希可以存储多达232-1个键值对。

Hash的常用命令
  • HSET:将哈希表中的字段设置为指定值
  • HGET:获取存储在哈希表中指定字段的值
  • HMSET:同时将多个field-value对设置到哈希表中
  • HGETALL:获取在哈希表中指定key的所有字段和值
  • HINCRBY:为哈希表中的字段值加上指定增量值
Hash的应用场景
  1. 用户信息存储:Hash类型可以用于存储用户信息,每个用户对应一个Hash,包含用户的各种属性。
String userKey = "user:1001";// 存储用户信息
jedis.hset(userKey, "name", "Tom");
jedis.hset(userKey, "age", "25");
jedis.hset(userKey, "city", "New York");// 获取用户信息
Map<String, String> userInfo = jedis.hgetAll(userKey);
  1. 购物车:Hash类型可以用于实现购物车功能,每个用户的购物车对应一个Hash,商品ID作为field,商品数量作为value。
String cartKey = "cart:1001";// 添加商品到购物车
jedis.hset(cartKey, "product:1001", "2");
jedis.hset(cartKey, "product:1002", "1");// 增加商品数量
jedis.hincrBy(cartKey, "product:1001", 1);// 获取购物车信息
Map<String, String> cart = jedis.hgetAll(cartKey);

缓存预热、雪崩 、穿透 、击穿

在这里插入图片描述

缓存预热

缓存预热是指在应用启动时,提前将一些热点数据加载到Redis缓存中,避免请求直接访问数据库,提高系统的响应速度。常见的缓存预热方式包括:

  • 使用@PostConstruct注解(Bean对象的生命周期第三阶段)
  • 第二种则是实现applicationRunner接口,重写run方法

推荐第二种 按照业务逻辑,我们需要加载完对应依赖,其他的Bean对象,再进行业务逻辑的处理

@Slf4j
@Component
public class StationDataInit implements ApplicationRunner {/*** 在项目启动前执行一些业务* 可以使用@PostConstruct注解  速度很快  但是不推荐* 推荐使用  实现 applicationRunner接口*/// @PostConstruct@PostConstructpublic void init() {log.debug("使用@PostConstruct注解实现在服务启动前去数据库里面获取信息");}@Overridepublic void run(ApplicationArguments args) throws Exception {log.debug("使用实现 applicationRunner接口实现在服务启动前去数据库里面获取信息");log.debug("从数据库里面获取所有的场站信息");List<StationPO> stationPOList = stationRepository.getAllStation();log.debug("获取数据存入到redis中");}

缓存雪崩

缓存雪崩是指在同一时段内大量的缓存key同时失效或Redis服务不可用,导致大量请求直接访问数据库,引起数据库压力骤增,甚至宕机。常见的解决方案包括:

  1. 给不同的Key设置不同的过期时间,避免同时失效。
  2. 利用Redis集群提高可用性。
  3. 给缓存的访问加上超时限制,避免数据库过载。
  4. 提前演练,确保数据库能够承受缓存全部失效的压力。
// 给不同的Key设置不同的过期时间
jedis.setex("key1", 3600, "value1");
jedis.setex("key2", 7200, "value2");
jedis.setex("key3", 10800, "value3");// 利用Redis哨兵或集群提高可用性
JedisPoolConfig poolConfig = new JedisPoolConfig();
// ...
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration().master("mymaster").sentinel("127.0.0.1", 26379).sentinel("127.0.0.1", 26380);
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(sentinelConfig, poolConfig);

缓存穿透

缓存穿透是指查询一个不存在的数据,因为不存在则不会写到缓存中,所以每次都会去请求数据库。如果大量的请求查询不存在的数据,就会给数据库带来很大的压力。常见的解决方案包括:

  1. 对不存在的key也缓存其value为null,设置较短的过期时间。
  2. 利用布隆过滤器快速判断key是否存在,避免缓存和数据库的查询。
// 缓存空值
String key = "non_existent_key";
String value = jedis.get(key);if (value == null) {// 从数据库查询value = db.get(key);if (value == null) {// 数据库中也不存在,缓存空值,过期时间设置较短jedis.setex(key, 60, "");} else {// 数据库中存在,写入缓存jedis.setex(key, 3600, value);}
}// 利用布隆过滤器判断key是否存在
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 1000000);if (!bloomFilter.mightContain(key)) {// key不存在,直接返回return null;
} else {// key可能存在,查询缓存String value = jedis.get(key);if (value != null) {return value;} else {// 缓存未命中,查询数据库// ...}
}

缓存击穿

缓存击穿是指一个热点Key在某个时间点过期,而恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。常见的解决方案包括:

  1. 使用互斥锁,只让一个线程构建缓存,其他线程等待缓存构建完毕后从缓存中读取数据。
  2. 不同的Key设置不同的过期时间,避免同时失效。
String lockKey = "lock:key";
String lockValue = UUID.randomUUID().toString();String value = jedis.get(key);
if (value == null) {// 获取分布式锁if ("OK".equals(jedis.set(lockKey, lockValue, "NX", "EX", 30))) {// 获取锁成功,查询数据库value = db.get(key);// 写入缓存jedis.setex(key, 3600, value);// 释放锁if (lockValue.equals(jedis.get(lockKey))) {jedis.del(lockKey);}} else {// 获取锁失败,等待一段时间后重试Thread.sleep(100);value = jedis.get(key);}
}

总结

Redis凭借其出色的性能和丰富的数据类型,已经成为现代互联网应用不可或缺的利器。深入理解Redis的各种数据类型及其适用场景,并结合Java客户端进行开发,可以帮助我们设计出更加高效、可靠的系统。同时,在使用Redis时也要注意一些高级主题,如缓存预热、缓存雪崩、缓存穿透和缓存击穿等,这些都是保证系统稳定运行的关键。

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

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

相关文章

YOLOv11改进策略【损失函数篇】| Shape-IoU:考虑边界框形状和尺度的更精确度量

一、本文介绍 本文记录的是改进YOLOv11的损失函数&#xff0c;将其替换成Shape-IoU。现有边界框回归方法通常考虑真实GT&#xff08;Ground Truth&#xff09;框与预测框之间的几何关系&#xff0c;通过边界框的相对位置和形状计算损失&#xff0c;但忽略了边界框本身的形状和…

IDEA几大常用AI插件

文章目录 前言列表GPT中文版TalkXBito AIIDEA自带的AI 前言 最近AI、GPT特别火&#xff0c;IDEA里面又有一堆插件支持GPT&#xff0c;所以做个专题比较一下各个GPT插件 列表 先看idea的plugins里支持哪些&#xff0c;搜索“GPT”之后得到的&#xff0c;我用下来感觉第一第二和…

[网络]抓包工具介绍 tcpdump

一、tcpdump tcpdump是一款基于命令行的网络抓包工具&#xff0c;可以捕获并分析传输到和从网络接口流入和流出的数据包。 1.1 安装 tcpdump 通常已经预装在大多数 Linux 发行版中。如果没有安装&#xff0c;可以使用包管理器 进行安装。例如 Ubuntu&#xff0c;可以使用以下…

【AI】深度学习的数学--核心公式

1 梯度下降 f ( x Δ x , y Δ y ) ≃ f ( x , y ) ∂ f ( x , y ) ∂ x Δ x ∂ f ( x , y ) ∂ y Δ y f(x\Delta x,y\Delta y) \simeq f(x,y)\frac{\partial f(x,y)}{\partial x}\Delta x\frac{\partial f(x,y)}{\partial y}\Delta y f(xΔx,yΔy)≃f(x,y)∂x∂f(x,y)​…

动手学深度学习(李沐)PyTorch 第 3 章 线性神经网络

3.1 线性回归 线性回归是对n维输入的加权&#xff0c;外加偏差 线性回归可以看作是单层神经网络 回归问题中最常用的损失函数是平方误差函数。 平方误差可以定义为以下公式&#xff1a; 常数1/2不会带来本质的差别&#xff0c;但这样在形式上稍微简单一些 &#xff08;因为当…

叶绿素透射反射率与波长

本文在分析巢湖水体反射光谱特征的基础上,通过对光谱反射率与叶绿素a 的浓度之间的关系进行分析研究,结果表明,单波段光谱反射率与叶绿素a浓度的相关系数较小,不宜用于估算叶绿素a浓度&#xff0e;光谱反射率比值RFo5.m/Rss.nm.和 690nm反射率的一阶微分均与叶绿素a浓度有较好的…

idea2023-快速搭建一个本地tomcat的javaWeb项目(从0到1保姆教学)

前言 如何在新版idea中搭建一个javaWeb项目&#xff0c;并且应用在物理的tomcat中&#xff0c;本文将进行从零到一&#xff0c;完成搭建步骤&#xff0c;以及相关注意事项的讲解。 为什么需要配置tomcat&#xff1f; 我们开发的javaWeb项目&#xff0c;最后都需要打包部署到真正…

C++基础---类和对象(上)

1.类的定义 C程序设计允许程序员使用类&#xff08;class&#xff09;定义特定程序中的数据类型。这些数据类型的实例被称为对象 &#xff0c;这些实例可以包含程序员定义的成员变量、常量、成员函数&#xff0c;以及重载的运算符。语法上&#xff0c;类似C中结构体&#xff0…

【网络篇】计算机网络基础知识详述(1)(笔记)

目录 一、因特网基础认识 1. 初识因特网 2. 网络服务 3. 网络协议 4. 网络边缘 5. 物理链路 &#xff08;1&#xff09;双绞铜线 &#xff08;2&#xff09;同轴电缆 &#xff08;3&#xff09;光纤 6. 网络的网络&#xff08;因特网&#xff09; 二、网络核心 1. …

unity_Occlusion_Culling遮挡剔除学习

unity_Occlusion_Culling遮挡剔除学习 文档&#xff1a; https://docs.unity.cn/cn/2019.4/Manual/occlusion-culling-getting-started.html没彻底搞明白&#xff0c;但是会用&#xff0c;虽然也不熟练 设置遮挡剔除 打开遮挡剔除面板 设置场景物体。设置为静态 设置场景 烘…

机器学习笔记(李宏毅老师2021/2022课程)【更新中】

目录 前言 课程预览 第一讲 机器学习基本概念 前言 本文主要记录在听李宏毅老师的课时对应做的课堂笔记 课程&#xff1a; (强推)李宏毅2021/2022春机器学习课程_哔哩哔哩_bilibili 课程预览 机器学习找函数 &#xff08;找一个人类写不出来的复杂函数&#xff09; 课程侧…

如何测试网络质量?

如何测试网络质量&#xff1f; 通过百度网盘分享的文件&#xff1a;winMTR 链接&#xff1a;https://pan.baidu.com/s/1Zfw4jciNhng35nfwBlF75Q 提取码&#xff1a;6622 –来自百度网盘超级会员V2的分享 下载WINMTR工具&#xff0c;在启动处输入www.baidu.com 判断方法&…

借助spring的IOC能力消除条件判断

shigen坚持更新文章的博客写手&#xff0c;记录成长&#xff0c;分享认知&#xff0c;留住感动。个人IP&#xff1a;shigen 在前边讲到了如何借助HashMap、枚举类、switch-case消除条件判断&#xff0c;这里讲到我们最常见的用spring的IOC能力来消除代码中的逻辑判断。其实大部…

2.点位管理开发(续)及设计思路——帝可得后台管理系统

目录 前言一、页面原型二、修改1、页面展示2、新增 3 、总结思路 前言 提示&#xff1a;本篇继续点位管理的改造 一、页面原型 页面展示新增 二、修改 1、页面展示 页面修改&#xff1a;修改标签换行、顺序顺序、地址过长时换行问题&#xff1b; <el-table v-loading…

JVM(HotSpot):字符串常量池(StringTable)

文章目录 一、内存结构图二、案例讲解三、总结 一、内存结构图 JDK1.6 JDK1.8 我们发现&#xff0c;StringTable移入了Heap里面。所以&#xff0c;应该想到&#xff0c;StringTable将受到GC管理。 其实&#xff0c;1.6中&#xff0c;在方法区中的时候&#xff0c;也是受GC管…

工单管理系统功能解析,企业运营效率提升利器

工单管理系统如ZohoDesk提供工单生成分配、跟踪、数据分析、客户服务管理及移动兼容等功能&#xff0c;提升效率、增强服务、便于监管和降低成本&#xff0c;是现代企业信息化建设的重要部分。 一. 工单管理系统一般有哪些功能 1. 工单生成与分配 工单管理系统的基础功能是创…

19 vue3之自定义指令Directive按钮鉴权

directive-自定义指令&#xff08;属于破坏性更新&#xff09; Vue中有v-if,v-for,v-bind&#xff0c;v-show,v-model 等等一系列方便快捷的指令 今天一起来了解一下vue里提供的自定义指令 Vue3指令的钩子函数 created 元素初始化的时候beforeMount 指令绑定到元素后调用 只…

Java增强for循环遍历集合删除指定值不安全问题

在这里因为remove方法有两种参数&#xff0c;一种是对象&#xff08;删除此元素&#xff09;&#xff0c;一种是Integer &#xff08;删除此下标对应的元素&#xff09;。恰好我对象类型就是Integer&#xff0c;所以或默认为删除下标对应元素&#xff0c;造成下标越界不安全。可…

Python的异步编程

什么是协程&#xff1f; 协程不是计算机系统提供&#xff0c;程序员人为创造。 协程也可以被称为微线程&#xff0c;是一种用户态内的上下文切换技术。简而言之&#xff0c;其实就是通过一个线程实现代码块相互切换执行。 实现协程有那么几种方法&#xff1a; greenlet&…

高校体育场小程序|高校体育场管理系统系统|体育场管理系统小程序设计与实现(源码+数据库+文档)

高校体育场管理系统小程序 目录 体育场管理系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道…