黑马点评Redis学习笔记

笔记按照教学视频讲解的顺序,并附上内容所在的视频分p位置

目录

P1 课程介绍

在这里插入图片描述
项目是前后端分离,不是微服务

P3 短信登录-基于session实现短信登录的流程

在这里插入图片描述
在这里插入图片描述
登录校验功能
在这里插入图片描述
在ThreadLocal中存储用户信息
在这里插入图片描述

MyBatisPlus支持对单表的CRUD
例如不用自己去写一条查询语句
在这里插入图片描述
原理是在结果的类中使用@TableName注解已经配置好CRUD的表名称了
在这里插入图片描述

P6 短信登录-实现登录校验拦截器

在这里插入图片描述
主要讲在controller之前加一个拦截器用于一个预先的处理,通过session获取用户信息

P7 短信登录-隐藏用户敏感信息

在这里插入图片描述
这节主要讲User和UserDTO的区别,就是说不要把不用的信息(或敏感的信息)返回给前端网页,这里要进行一个类型转换
这两个对象的属性信息拷贝可以用hutool工具包的BeanUtil.copyProperties()方法

P8 短信登录-session共享的问题分析

在这里插入图片描述
在这里插入图片描述

P9 短信登录-Redis代替session的业务流程

在这里插入图片描述
使用redis的时候这里的key不能像使用session一样都使用code,因为每个session都有一个sessionID可以保证不冲突,
但这里是redis集群,它的key必须唯一,才能保证获取到正确的值
在这里插入图片描述
在这里插入图片描述
所以可以使用手机号作为key(手机号不安全有泄露风险),但推荐使用一个随机字符串作为key
在这里插入图片描述
在redis中存储一个对象可以使用hash结构(相比string结构更好),
hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD,而如果使用string的话只能整体删掉重新赋值
在这里插入图片描述

P10 短信登录-基于Redis实现短信登录

在这里插入图片描述
在redis中存储用户的信息的时候(通过token作为key)会设置一个过期时间(比如30分钟),需求是用户在不操作30分钟后过期,而不是一直操作也会过期
方法是,可以在拦截器中刷新key的时间

注意StringRedisTemplate和RedisTemplate的区别,
前者要求存的数据只能是字符串,并且这两个存的数据不能相互查到
在这里插入图片描述
在这里插入图片描述
通过stringRedisTemplate存储String字符串数据、获取数据
stringRedisTemplate.opsForValue().set()
stringRedisTemplate.opsForValue().get()
通过stringRedisTemplate存储Hash数据、获取数据、设置过期时间
stringRedisTemplate.opsForHash().putAll()
tringRedisTemplate.opsForHash().entries()
stringRedisTemplate.expire()
使用hutool的BeanUtil.beanToMap方法将Bean转为Map

P11 短信登录-解决状态登录刷新的问题

在这里插入图片描述
问题:在拦截器中刷新用户的key时间只能针对需要登录的网页(因为只拦截需要登录的网页),我们希望用户在访问不需要的登录的网页的时候也起到一个刷新用户key的效果
解决:在拦截器前再设置一个拦截器,第一个拦截器拦截一切路径并刷新key,第二个拦截器才做真正的拦截
在这里插入图片描述

P12 什么是缓存

在这里插入图片描述
在这里插入图片描述
缓存可以减少后端负载,减少相应时间,但会带来数据一致性成本,也会引入缓存穿透击穿等问题

P13 添加商户缓存

在这里插入图片描述
mybatisplus也提供业务层的接口,可以直接查询

在这里插入图片描述
在这里插入图片描述
在客户端与数据库之间添加缓存
在这里插入图片描述

P14 缓存练习题分析

在这里插入图片描述
用上述类似的方法给商户类型列表添加缓存,其中的逻辑是相同的,不同点在于是对一个List进行Redis的String的存储和读取
利用hutool的JSONUtil工具包调用toList方法进行字符串转对象数组

在这里插入图片描述

P15 缓存更新策略

在这里插入图片描述
在这里插入图片描述
通常来说更常用的是第一种策略,由自己在更新数据库时更新缓存
第二种策略整合的服务非常复杂,第三种策略需要考虑缓存宕机数据丢失的问题
在这里插入图片描述
在这里插入图片描述
先操作缓存还是先操作数据库,都可能导致程安全问题,避免多线程下缓存数据库数据不一致
但先操作数据库再删除缓存的方式更好,发生线程安全问题概率较低
在这里插入图片描述
在这里插入图片描述

P16 实现商铺缓存与数据库的双写一致

在这里插入图片描述
当要更新数据库的时候,先更新数据库,再删除缓存(为了防止删除失败数据库又更新了,加一个Transactional注解来回滚)

P17 缓存穿透的解决思路

在这里插入图片描述
缓存穿透是指用户请求一个并不存在的数据,故意不命中缓存来消耗数据库的资源
第一种解决方法:可以将这些空对象缓存起来,避免相同的空请求重复地打到数据库
缓存空的对象只能解决重复请求同一个空对象的情况,如果每次请求的都不一样会占用大量的缓存空间(比如随机生成一个请求大概率是不存在的),
此时可以用第二种方法,先用过滤器判断再去查redis缓存

第二种方法:在缓存之前加一个布隆过滤器,这个过滤器可以判断请求的东西在数据库中是否存在(利用bit数组实现)
由于布隆过滤器的误判性,它只能确定请求东西在数据库中一定不存在(此时直接拒绝),或者在数据库中大概率存在(先放行但仍小概率不存在),
原理是一个东西如果加入了过滤器中,那么它一定会被过滤到,也有可能没加入过滤器的东西也被过滤了
在这里插入图片描述

P18 编码解决商铺查询的缓存穿透问题

在这里插入图片描述
采用缓存空对象的方法解决的逻辑流程
在这里插入图片描述
除了以上两种解决方法之外,也有一些其他的手段来解决穿透
比如增加id的复杂的避免有规律的自然数,可以设置id的长度等
然后根据自己制定的id规则来做格式校验,可以提前阻止一部分请求
或者要求查询的用户具有某些权限,比如要先登录等,不同权限的用户查询的频率有不同限制等
在这里插入图片描述

P19 缓存雪崩问题及解决思路

在这里插入图片描述
给TTL过期时间添加一个随机值,避免同时失效
采用集群来提高可用性
降级限流意为给某些业务降低服务质量,返回拒绝服务
给请求过程的每个环节添加缓存,可以是nginx、redis、JVM、数据库等
在这里插入图片描述

P20 缓存击穿问题及解决方案

在这里插入图片描述
在这里插入图片描述
两种解决方案的时序图
在这里插入图片描述
互斥锁在重建缓存时其他线程只能等待,此时服务不可用,如果重建缓存的业务中涉及到的缓存也正在发生缓存重建,可能就会发生死锁。
逻辑过期在缓存中加了一个自定义字段表示数据的过期时间(不是真正的过期),实际上设置它永不过期,如果查询到数据逻辑过期了,那么就进行重建,重建期间返回旧的数据,保证了服务的可用性。

这两种方法如何选择,其实是在一致性和可用性直接选择,
分布式系统中也面临一致性和可用性之间的抉择问题,在这里互斥锁选择了一致性,逻辑过期选择了可用性
在这里插入图片描述

P21 利用互斥锁解决缓存击穿问题

在这里插入图片描述
在这里插入图片描述
在某个缓存失效的情况下,有多个线程(比如1000个)发起查询请求,只有第1个线程去重建缓存(去查数据库,只查1次),其它线程等待
互斥锁可以用redis中的setnx锁来实现,这个锁的数据只能在创建的时候赋值(赋给它1),值不能被修改,只能被删除key
在这里插入图片描述
线程等待使用Thread.sleep(),这个方法需要解决异常,往上抛

利用jmeter压力测试工具,发起1000个http请求,
在这里插入图片描述
可以在结果中看到所有请求都成功得到了是数据,也可以在也可以在汇总报告中看到吞吐量

在这里插入图片描述

P22 利用逻辑过期解决缓存击穿问题

在这里插入图片描述
在这里插入图片描述
首先考虑逻辑过期这个字段设置在哪里的问题,因为存储的对象本身是不带这个字段的,可以在对象中添加一个字段,但这会修改原来的代码,不推荐
还有一种做法是使用继承,新定义一个带逻辑过期字段的类,它继承原来的那个类。
推荐的做法是定义一个对象,有两个属性,一个属性存过期时间,另一个属性存Object字段,这样所有的对象都可以进行存储。

通过java.time.LocalDateTime获取时间
LocalDateTime.now()得到当前时间,LocalDateTime.now().plusSeconds(秒数)得到当前时间之后一刻时间

测试步骤:
1、往缓存里面存数据(可以运行单元测试方法),缓存里面一定要有一个数据,不管是新的还是旧的,否则被认为要查询的东西不存在
2、在数据库中修改数据,此时数据库的数据是最新的,缓存里面的数据是旧的
3、通过jmeter在1秒内发起100个请求,可以看到前面部分的请求获取的是旧数据(缓存里面旧的),后面部分的请求得到的是新数据(缓存重建之后的新的)
4、这个过程中只发生了1次缓存重建(比如数据库查询),表明它是线程安全的

P23 封装Redis工具类

在这里插入图片描述
在这里插入图片描述
将这些方法编写到一个工具类中,难点在于:1,类型不确定用泛型,2,方法不确定用函数式编程。这两者都由调用者来确定。
返回的类型不确定,id的类型不确定,利用泛型在类型不确定的情况下指定数据类型,
由使用这个方法的调用者告诉我们类型是什么,例如这里的商品类型Shop
在这里插入图片描述
由于查询数据库的方式是不确定的,让方法的调用者传一个参数告诉方法如何查询数据库,需要一个参数并带有返回值,所以进行函数式编程,
用java里的Function来实现,这里传入了一个函数,命名为dbFallback,参数为ID和返回类型R都是泛型,调用apply来执行传入的函数
在这里插入图片描述
这是调用方法的传入参数,它说明了返回一个Shop商铺类型,查询数据库的方式为getById(),
id2 -> getById(id2) 由于id2相同可写为 this::getById
在这里插入图片描述

P24 缓存总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这篇笔记是关于黑马点评项目中使用Redis学习笔记笔记中的图片来源于黑马ppt,并提供了联系方式,如果有侵权问题可以联系删除。笔记内容包括了Redis的安装配置以及一些相关的知识点。需要注意的是,笔记中的配置是按照黑马2022的Redis进行的,仅供学习参考,并可以自由转载。另外,作者使用的是云服务器,所以IP配置不是127.0.0.1,大家需要根据自己的实际情况进行配置。在笔记中还对一些知识进行了补充,例如设置RedisSerializer来解决乱码问题。此外,笔记还提到了Redis的5种常见数据结构,包括String、List、Set、Hash和ZSet。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [redis项目-黑马点评 项目笔记](https://blog.csdn.net/qq_48617775/article/details/127497077)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis黑马2022笔记(基础篇)](https://blog.csdn.net/m0_56079407/article/details/123453958)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值