redis笔记大全

redis笔记大全

跟着bilibili黑马程序员的老师学习的笔记😀

1、Redis命令和数据类型

(1) 通用命令

  • KEYS:查看符合模板的所有key
  • DEL:删除指定的key
  • EXISTS:判断key是否存在
  • EXPIRE :给一个key设置有效期,有效期到期时该key会被自动删除(① -1表示永久有效期,② -2表示已过期,③ 单位是
  • TTL:查看一个KEY的剩余有效时间

(2) 字符串类型


如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储:


(3) KEY命名规范

(4) Hash类型

(5) List类型

Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表。

  • 有序
  • 元素可以重复

常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。



(6) Set类型

Redis的Set结构与Java中的HashSet类似。

  • 无序
  • 元素不可重复
  • 支持交集、并集、差集等功能

(7) SortedSet类型

Redis的SortedSet是一个可排序的set集合。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序。

  • 可排序
  • 元素不重复

因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。



2、Java操纵Redis👉SpringDataRedis

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。

官网地址:https://spring.io/projects/spring-data-redis

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
    支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。

为了节省内存空间,一般并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

java 复制代码
    @Test
    public void testStringRedisTemplate() throws JsonProcessingException {
        // JSON序列化工具
        ObjectMapper objectMapper = new ObjectMapper();
        // 把学生对象转换为JSON字符串
        Student stu = Student.builder().id(1).name("迪丽热巴").score(666.666).build();
        String stuStr = objectMapper.writeValueAsString(stu);
        // 存入Redis
        stringRedisTemplate.opsForValue().set("success:stu:001", stuStr);

        // 读数据
        String stuJson = stringRedisTemplate.opsForValue().get("success:stu:001");
        // 把学生JSON字符串转换为学生对象
        Student stuFromRedis = objectMapper.readValue(stuJson, Student.class);
        System.out.println(stuFromRedis);
    }

3、ThreadLocal和HandlerInterceptor实现简单接口拦截

  • ThreadLocal在同一线程内共享登录用户信息
  • HandlerInterceptor拦截接口,判断当前用户是否登录(通过Session或携带Redis登录令牌)。登录了则往ThreadLocal中存储用户信息,否则返回401

4、使用HttpSession实现登录功能,存储用户信息的弊端

  • 集群的session共享问题:多台Tomcat并不共享session存储空间,当请求切换到不同tomcat服务时导致数据丢失的问题。

session的替代方案应该满足:

  • 数据共享(让多个微服务,多台Tomcat都可以访问登录用户的信息)
  • 内存存储(和session一样都是基于缓存的)
  • key、value结构

Redis就非常合适😄


  • 发送验证码的时候:用手机号作为KEY,验证码值作为VALUE存储到Redis

  • 登录/注册的时候:根据手机号从Redis查询验证码,判断用户传递的验证码是否正确;登录/注册完成后,生成随机字符串(token)作为KEY,用户信息作为VALUE存储到Redis。然后,把token传递给客户端。客户端需要保存token,以后每次访问接口的时候都要携带token。我会在LoginInterceptor中从Header中获取token值,根据token值从redis中查询用户信息。如果没有查询到用户信息就会返回401,查询到了用户信息后才会放行。存储登录的用户信息的时候,VALUE用的是Redis的Hash类型。

  • 保存登录的用户信息,可以使用String结构,以JSON字符串的形式来保存,但会有额外内存占用,并且不方便修改用户信息中的某一个值。

  • Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD,并且内存占用更少。

5、数据库和缓存数据一致性

  • 自己写代码实现👉当更新数据库数据的时候,把更新的数据同步同步到redis中

  • 在同步redis数据的时候,采取缓存的策略(可以避免过多无效的写操作),等下次查询缓存的时候,缓存未命中的时候,再查询数据库并更新缓存

  • 缓存和数据库操作保证一致性(要么同时成功,要么同时失败)❓ ① 如果是单体架构👉把缓存操作和数据库操作放在同一个事务中;② 如果是分布式架构👉使用分布式事务保证两个操作的一致性

  • 应该操作完数据库后,再删除缓存(修改完数据库后,删除缓存的操作执行速度是很快的,产生并发问题的可能性低)

6、缓存穿透

  • 缓存穿透:客户端请求的数据在缓存中和数据库中都没有,这些请求都会打到数据库。

  • (1) 缓存空对象,并设置较短的过期时间(实现简单😀 但是会有额外的内存消耗,并且可能造成数据的短期不一致)

  • (2) 布隆过滤(占用内存少😀但是实现复杂,会有误判的可能)

🌼 提前预判:布隆过滤器是一种空间高效的概率型数据结构,会预先将所有合法的缓存 key(如数据库中存在的用户 ID、商品 ID)存入其中。

🌼 拦截无效请求:当请求到达时,先通过布隆过滤器校验 key(如数据库中存在的用户 ID、商品 ID) 是否存在:

① 若过滤器判定 "不存在",则直接返回空结果,无需查询缓存和数据库,拦截无效请求;

② 若判定 "可能存在" ,再继续查询 Redis 缓存,缓存未命中时再查数据库。

🌼核心特性:布隆过滤器可能误判 不存在为存在,判定不存在则一定不存在,确保所有无效 key 都被拦截,从源头避免缓存穿透(即请求不断查询不存在的 key,绕过缓存直击数据库)。

7、缓存雪崩

  • 缓存雪崩:同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

📕解决方案:

① 缓存预热的时候,缓存的数据的过期时间增加随机值(保证这些数据不会在同一时刻都过期)

② 利用Redis集群提高服务的可用性

③ 给缓存业务添加降级限流策略(当redis服务宕机的时候,拒绝部分请求,避免给数据库带来巨大压力)

④ 给业务添加多级缓存

8、缓存击穿

  • 缓存击穿问题(热点Key问题):一个被高并发访问 并且缓存重建较复杂的key突然失效了,无数的请求会在瞬间给数据库带来巨大的冲击。

  • 互斥锁解决缓存击穿:当热点key过期,多个请求到达系统的时候,只允许一个请求(线程)执行缓存重建操作,其他请求都等待(每个一段时间尝试从redis中获取缓存重建的数据)。保证了数据的一致性😀,但是会有多个线程等待缓存重建,系统性能收到影响。
  • 添加逻辑过期时间解决缓存击穿:给热点key增加逻辑过期时间(不要给热点key增加redis的ttl,让热点key永不过期)。当一个热点key过期的时候,当一个线程A发现它过期了,该线程A创建一个新线程B进行缓存重建操作,然后返回redis中的旧数据。其他线程发现热点key过期并且已经有其他线程进行缓存重建了,其他线程就直接返回旧数据。

8.1 基于redis的setnx实现互斥锁

  • redis的setnx命令会当某个key不存在的时候才给该key设置值。Set the value of a key, only if the key does not exist (只有这个key不存在的时候才给其设置值)
  • setnx lock 6 是获取锁
  • del lock 是释放锁(删除锁是释放锁)
  • 要给key设置过期时间,避免因为某些原因导致死锁

  • 热点key一般会提前进行缓存预热,把热点key数据提前存入redis

8.2 基于逻辑过期实现互斥锁的时候要开启新线程进行缓存重建

  • 这里可以用JDK的线程池
java 复制代码
private ExecutorService executors= Executors.newFixedThreadPool(8);
相关推荐
hssfscv14 小时前
JavaWeb学习笔记——后端实战1_准备工作
笔记·后端·学习
资生算法程序员_畅想家_剑魔14 小时前
Java常见技术分享-26-事务安全-锁机制-作用与分类
java·开发语言·数据库
Vic1010115 小时前
PostgreSQL 中 nextval() 的线程安全性解析
java·数据库·postgresql
写代码的小阿帆15 小时前
Redis缓存健壮性——穿透、雪崩与击穿防护
数据库·redis·缓存
wangqiaowq15 小时前
使用 mysqldump 导出 + mysql 导入
数据库
qq_3176203116 小时前
第23章-中级项目练习案例(15个)
数据库·爬虫·web开发·python项目·api开发·python案例
是三好16 小时前
SQL 性能分析及优化
android·数据库·sql
indexsunny16 小时前
互联网大厂Java面试实战:从Spring Boot到微服务的逐步深入
java·数据库·spring boot·微服务·kafka·监控·安全认证
小光学长16 小时前
ssm手工艺品交易平台4xccvou1(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring