Redis 的缓存策略

在这里插入图片描述

  各位小伙伴们大家好,欢迎来到这个小扎扎的Redis 6专栏,在这个系列专栏中我对B站黑马的Redis教程进行一个总结,鉴于 看到就是学到、学到就是赚到 精神,这波依然是血赚 ┗|`O′|┛

💡Redis知识点速览

  • 🍖 Redis缓存中间件
    • 🥩 缓存是什么
    • 🥩 Redis缓存已查询数据
    • 🥩 redis缓存中间件实践
  • 🍖 缓存更新
    • 🥩 缓存更新的三个策略
    • 🥩 主动更新策略的三种方案
    • 🥩 主动更新的代码实现

🍖 Redis缓存中间件

🥩 缓存是什么

  所谓缓存就是数据交换的缓冲区(称作Cache [ kæʃ ] ),是一个临时存贮数据的地方,一般读写性能较高。CPU的运算速度要远远大于内存的读写速度,这样会使CPU花费很长时间等待数据从内存的获取或者写入,因此缓存的出现主要就是为了解决CPU运算速度与内存读写速度不匹配的矛盾
  说了半天缓存和web开发有什么必要的联系嘛?当然有,在整个web开发的各个阶段都可以使用到不同缓存,比如浏览器缓存页面等静态资源,tomcat服务器应用层缓存查询过的数据,数据库缓存索引信息等在这里插入图片描述缓存的优点

  • 降低后端负载
  • 提高读写效率,降低响应时间

缓存的缺点

  • 数据更新前后缓存区中该数据的一致性难保证
  • 解决数据一致性需要复杂的业务代码,提高后续维护成本
  • 集群模式下提高运维成本

🥩 Redis缓存已查询数据

  在未使用缓存之前,用户的所有请求都会直接访问数据库,但是使用redis作为缓存之后就不一样了。用户的请求会是先在redis中查找,如果查到也就是命中的话就直接返回客户端,如果未命中的话就去数据库中查找,查到有结果就将查询到的结果写入redis中,然后返回给客户端;未查到结果就返回404状态码在这里插入图片描述

🥩 redis缓存中间件实践

  黑马点评中有这么一个业务:点击商铺图片会通过id查询该商铺的相关信息,如果使用redis缓存的话,后期再访问该商铺的话就会直接到redis中查询,可以大大缩短查询所需时间

collector中定义与前端交互的方法,前端请求/shop-type/list?id=xx

@RestController
@RequestMapping("/shop")
public class ShopController {@Resourcepublic IShopService shopService;/*** 根据id查询商铺信息* @param id 商铺id* @return 商铺详情数据*/@GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {return shopService.queryById(id);}
}

编写typeService里业务逻辑方法getList的接口和实现类,逻辑参考Redis缓存已查询数据的相关分析

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {// 从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);// 判断该商铺是否存在if (StrUtil.isNotBlank(shopJson)) {// 存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 不存在查询数据库Shop shop = getById(id);if (shop == null) {// 数据库中不存在直接返回错误信息return Result.fail("店铺不存在");}// 数据库中存在写入redisstringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop));// 返回return Result.ok(shop);}
}

  经实验验证得知,使用redis缓存未命中时查询耗时将近200毫秒,后续查询命中之后只需几毫秒,可见redis作为缓存中间件对数据读取的功效还是很高的

🍖 缓存更新

  之前介绍redis的时候介绍过redis缓存的一些缺点,比如数据库中数据更新前后缓存区中该数据的一致性难保证,该怎么应对redis缓存的这个缺点呢?这就引出接下来的学习内容——缓存更新策略

🥩 缓存更新的三个策略

  内存淘汰: redis底层的内存淘汰机制,无需我们自己维护,当内存不足时自动淘汰部分数据,下次查询时更新缓存。这种机制的优点是维护成本极低,但是缺点也很明显,由于淘汰数据的不确定性导致很难保证数据的一致性
  超时剔除: 向redis中添加缓存数据的时候设置TTL时间,到期后自动删除缓存,下次查询时更新缓存。这种机制维护成本不是很高,但是数据一致性同样无法做到很高的保证,因为设置之后数据的有效期就固定了,但是更新时间不固定,若是数据在超时剔除之前发生更新然后查询,得到的仍是更新之前的数据
  主动更新: 使用代码在修改数据库的同时更新缓存。这种策略能够保证很高的数据一致性,但是伴随而来的就是更高的维护成本,要在每一个更改语句后面加上redis缓存更新

  具体使用哪种策略取决于该业务对数据一致性的需求:一致性需求不高的话,可以使用内存淘汰策略。一致性需求较高的话,可以使用主动更新加上超时剔除策略,保证了较高的一致性

🥩 主动更新策略的三种方案

  代码(Cache Aside Pattern):最直接的一种方案,使用代码在修改数据库的同时更新缓存
  服务(Read/Warite Through Pattern):将redis缓存与数据库整合为一个服务,由这个服务来维护数据的一致性,在更新数据库时只需要调用该服务即可,无需关心服务底层的业务逻辑,类似于封装。但是市面上没有现成的服务可以使用,自己封装这么一个服务也很复杂,所以说这种方案可用性很差
  写回(Write Behind Caching Pattern):所有数据库的CRUD操作都在redis缓存中完成,由另外一个独立的线程异步的将缓存中的数据持久化到数据库中,以此来保证数据的最终一致。这种方案有个很大的好处,那就是极大地减少了对数据库的操作,如果主线程在另一个线程两次持久化之间对redis中的数据操作多次,数据库中只会执行最后一次操作,而不是也操作多次。但是也有坏处,那就是如果还没等到另一个线程持久化数据库,此时redis缓存发生宕机,缓存大多数在内存中,此时发生宕机就会导致缓存中的数据消失,数据库中的数据就与宕机前redis中的数据不一致

  综上所述,虽然Cache Aside Pattern方案是最复杂的一个,但是他也同样是最可靠的一个,于是我们选择它来进行接下来的代码学习

主动更新策略注意项
  数据库发生更新的时候直接删除缓存中的该数据,而不是跟着更新缓存,因为如果发生连续修改多次的情况,更新缓存的话更新次数等于数据库的更新次数;如果是删除缓存数据的话就只需要删除一次,下一次查询直接从数据库中查询再写入缓存。
  删除缓存数据和数据库操作应该保证原子性,也就是说删除缓存数据操作和数据库操作应该同时成功或者同时失败,那么该如何实现呢?单体式系统中,可以通过将两个操作放在一个事务中来完成;分布式系统中可以利用TCC等分布式事务方案来实现
  删除缓存数据操作和数据库操作的先后顺序是什么? 应该是先写数据库再删除缓存,原因是这种方式发生线程安全性问题的可能较小

🥩 主动更新的代码实现

controller层前端交互

/*** 更新商铺信息* @param shop 商铺数据* @return 无*/
@PutMapping
public Result updateShop(@RequestBody Shop shop) {// 写入数据库return shopService.update(shop);
}

  需要server的update方法,创建接口和实现类完成业务逻辑代码编写。主动更新+超时剔除的策略就只有两步,那就是在写缓存的时候设置超时时间,更新数据库之后删除缓存

// 数据库中存在写入redis的时候设置超时时间
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);/*** 更新商铺信息* @param shop  商铺信息* @return 前端返回数据*/
@Override
@Transactional
public Result update(Shop shop) {if (shop.getId() == null) {return Result.fail("店铺id不能为空");}// 更新数据库updateById(shop);// 删除缓存stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + shop.getId());// 返回return Result.ok();
}

在这里插入图片描述

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

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

相关文章

关闭后天 树莓派_陪你一起玩树莓派-系统安装

从今天就开始我们的树莓派之旅&#xff0c;心情是不是有点小激动&#xff1f;我们拿到一个树莓派是一个裸机。我们要准备一张16G的高速TF闪存卡&#xff0c;一个5V/2A的USB电源和一根micro B的 usb线。装机步骤&#xff1a;一、下载树莓派系统1、浏览器打开树莓派官方网站 http…

简单的签到代码_PHP实现一个小小的签到功能,到底用MySQL还是Redis?

来源 | http://suo.im/5EWN3k今天&#xff0c;看下签到功能怎么选择&#xff1f;现在的网站和app开发中&#xff0c;签到是一个很常见的功能&#xff0c;如微博签到送积分&#xff0c;签到排行榜~微博签到如移动app &#xff0c;签到送流量等活动&#xff0c;移动app签到用户签…

【Redis 6】缓存穿透、缓存雪崩、缓存击穿(附解决方案、代码)

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的Redis 6专栏&#xff0c;在这个系列专栏中我对B站黑马的Redis教程进行一个总结&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波依然是血赚 ┗|&#xff40;O′|┛ &#x1f4a1;Redis知识点速览&#…

8软件遇到的问题及解决方法_Excel工作表中的8个常见问题,你一定遇到过,附解决方法...

在Excel工作表中&#xff0c;最常用的还是一些技巧&#xff0c;如果能够熟练掌握&#xff0c;对于工作效率的提高绝对不是一点点哦&#xff0c;结合工作实际&#xff0c;小编对工作中常见的问题进行了总结&#xff0c;一共有8类&#xff0c;你一定也遇到过……一、Excel工作表常…

unity着色器和屏幕特效开发秘笈_Oculus研发分享:开发移动VR内容时应避免的PC渲染技术...

查看引用/信息源请点击&#xff1a;映维网开发移动VR内容时应避免的PC渲染技术&#xff08;映维网 2019年11月25日&#xff09;有不少开发者都是以与PC相同的方式来开发Quest游戏&#xff0c;但这可能会导致优化性能方面出现大量困难。Oculus软件工程师特雷弗达什&#xff08;T…

Java包装类、java中的方法传参机制:按值调用

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏&#xff0c;在这个系列专栏中我将记录浅学这本书所得收获&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波简直就是血赚 &#x1f4a1;涉及的知识点速通&#x1f6eb; 方法…

尤克里里怎么样_尤克里里和吉他区别?尤克里里与吉他相比有什么不可替代的优势...

尤克里里和吉他有什么区别&#xff1f;想必大家都见过尤克里里吧&#xff0c;就是类似吉他形状的一种小型弦拨乐器。我们可以简单的认为&#xff1a;尤克里里是简化版本的吉他&#xff0c;更加简单&#xff0c;更加便宜。小编弹的就是尤克里里2.从外观上&#xff1a;吉他很大&a…

饿汉懒汉单例设计模式的使用及区别、java中的import关键字

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏&#xff0c;在这个系列专栏中我将记录浅学这本书所得收获&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波简直就是血赚 &#x1f4a1;涉及的知识点速通&#x1f6eb; 关于…

广电运通不好进吗_我可以说郑州新风的安装大部分都是垃圾吗?

说郑州的新风安装都是垃圾&#xff0c;这话很无礼&#xff0c;很自大&#xff0c;很傲慢&#xff0c;但是我能说确实是这样嘛&#xff1f;其实包括我以前安装的也不合格——虽然我不是故意的。这几年见过许多家同行安装的新风&#xff0c;可以说目前见到的很多家都不合格&#…

Java迭代器和Collection接口

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏&#xff0c;在这个系列专栏中我将记录浅学这本书所得收获&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波简直就是血赚 &#x1f4a1;涉及的知识点速通&#x1f6eb; 关于…

私钥经过哈希计算可以产生公钥_「区块链基础概念100」:公钥和私钥 | 027

免责声明&#xff1a;本文旨在传递更多市场信息&#xff0c;不构成任何投资建议。文章仅代表作者观点&#xff0c;不代表火星财经官方立场。小编&#xff1a;记得关注哦投资区块链&#xff0c;猛戳&#xff1a;火星财经App下载来源&#xff1a;学习区块链原文标题&#xff1a;「…

关于List集合类ArrayList、LinkedList、Vector详解

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏&#xff0c;在这个系列专栏中我将记录浅学这本书所得收获&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波简直就是血赚 &#x1f4a1;涉及的知识点速通&#x1f6eb; 关于…

关于Set集合类你都知道什么?来自《卷Ⅰ》的灵魂提问

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的《Java核心技术 卷Ⅰ》笔记专栏&#xff0c;在这个系列专栏中我将记录浅学这本书所得收获&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波简直就是血赚 &#x1f4a1;涉及的知识点速通&#x1f6eb; 关于…

流程图虚线框表示什么_UI设计|APP的交互线框布局设计

一.流程图设计流程图(Flow Chart)&#xff1a;用图示的方式反映出特定主体为了满足特定需求而进行的有特定逻辑关系的一系列操作过程。流程图的四种基本结构&#xff1a;顺序结构&#xff0c;条件结构(又称选择结构)&#xff0c;循环结构&#xff0c;分支结构。1.流程图的常用符…

使用Redis完成商品秒杀业务

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的Redis 6专栏&#xff0c;在这个系列专栏中我对B站黑马的Redis教程进行一个总结&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波依然是血赚 ┗|&#xff40;O′|┛ &#x1f4a1;Redis知识点速览&#…

表格列隐藏_【excel每日提升】Excel隐藏列,不让别人打开!

【新朋友】点击标题下面蓝色字“王俊东“关注。 【老朋友】点击右上角&#xff0c;转发或分享本页面内容。excel系列课程excel特效系列课程开始了&#xff0c;今天第2节&#xff01;第1节&#xff1a;Excel有公式的单元格标记颜色&#xff0c;很简单&#xff01;第2节&#xf…

“毕业季”|一个java开发实习生的OFFER之路

哈喽哈喽大家好&#xff0c;这里是小扎扎的博客。相信有关注过我的好盆友们可能会发现我已经有一段时间没有出来划水了&#xff0c;那么这段时间小扎扎都在干什么呢&#xff1f;没错&#xff01;我确实是去找实习了&#xff01;接下来就给大家介绍一下本次战役的战况如何 活动地…

virtualbox 该内存不能为written_系统提示“该内存不能为read”的原因和解决办法...

我们单位的电脑经常显示这个对话框&#xff0c;已经有好几年了&#xff0c;单位的老头们都不怎么懂电脑&#xff0c;我本人也不爱管闲事。但是出现这种对话框的原因是什么呢&#xff1f;又怎么解决呢&#xff1f;一般电脑经常出现蓝屏和死机&#xff0c;而且频繁出现。有时会出…

插件properties_Mybatis3系列 - 4. mybatis-config的properties属性详解

前两章简单的讲解了MyBatis的使用方式. 接下来先全局的说一下MyBatis的全局的xml配置详细说明.XML格式定义-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">configuration 的映射文件(根据定义顺序说明)properties 属性…

【Redis 6】秒杀业务——分布式锁

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的Redis 6专栏&#xff0c;在这个系列专栏中我对B站黑马的Redis教程进行一个总结&#xff0c;鉴于 看到就是学到、学到就是赚到 精神&#xff0c;这波依然是血赚 ┗|&#xff40;O′|┛ &#x1f4a1;Redis知识点速览&#…