redis和数据库数据不一直问题,缓存常见的三大问题

文章目录

    • 数据一致性
    • 缓存常见问题
      • 缓存穿透
      • 缓存击穿
      • 缓存雪崩

数据一致性

1 思路

  • 查询数据的时候,如果缓存未命中,则查询数据库,将数据写入缓存设置超时时间
  • 修改数据时,先修改数据库,在删除缓存。

2 代码实现

  • 修改更新方法,添加超时时间
 @Overridepublic Result queryById(Long id) {//1 redis中查询商户缓存String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);//2 判断是否存在if(StrUtil.isNotBlank(shopJson)){//3存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//4 不存在根据id去数据库查询Shop shop = this.getById(id);//5 数据库也不存在,返回错误if(shop==null){return Result.fail("店铺不存在");}//6 存在则写入redis中redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);//7 返回return Result.ok(shop);}
  • 修改ShopController
  @PutMappingpublic Result updateShop(@RequestBody Shop shop) {// 写入数据库//shopService.updateById(shop);//return Result.ok();return  shopService.update(shop);}
  • 修改service代码 延时双删策略
  @Overridepublic Result update(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不存在");}// 删除缓存redisTemplate.delete("cache.shop:" + id);// 更新数据库updateById(shop);Thread.sleep(800);// 删除缓存redisTemplate.delete("cache.shop:" + id);return Result.ok();}

3 修改完代码以后,将所有的缓存删除,执行查询操作,多了超时
在这里插入图片描述

4 用postman执行修改方法: localhost:8081/shop

{"area":"大关","sold":3035,"address":"金华路锦昌文华苑29号","name":"102茶餐厅","x":120.149192,"y":30.316078,"typeId":1,"id":1
}

在这里插入图片描述

执行完成以后,数据库的数据发生改变,查看redis的数据已经删除了。


这样能保证百分之99的数据一致性问题,无法保证完全一致性,这个适合小项目,数据一致性要求不高的地方使用,如果对数据一致性要求高的不建议使用,建议使用数据库和redis数据同步进行的操作,可以上csdn进行搜索查看实现方式。

缓存常见问题

缓存穿透

客户端请求的数据,在数据库和redis中都不存在,这样缓存永远都不会生效,请求最终都到了数据库上。

解决方案:

  • 当在数据库查询的结果也不存在的时候,可以返回null值给redis,并且设置TTL

在这里插入图片描述

  • 布隆过滤器

    在这里插入图片描述

布隆过滤器是一种数据结构,底层是位数组,通过将集合中的元素多次hash得到的结果保存到布隆过滤器中。主要作用就是可以快速判断一个元素是否在集合里面,但是因为算法的原因,也有一定概率的错误。

开发的时候我们一般选择空值值方式。

  • 代码方式实现

    在这里插入图片描述

根据id查询的时候,如果信息不存在,则要将空值写入redis,并设置空值过期时间

@Overridepublic Result queryById(Long id) {//1 redis中查询商户缓存String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);//2 判断是否存在if(StrUtil.isNotBlank(shopJson)){//3存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}if(shopJson!=null){return Result.fail("店铺不存在");}//4 不存在根据id去数据库查询Shop shop = this.getById(id);//5 数据库也不存在,返回错误if(shop==null){// 空值写入redis中redisTemplate.opsForValue().set("cache.shop:" + id,"",3, TimeUnit.MINUTES);return Result.fail("店铺不存在");}//6 存在则写入redis中redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);//7 返回return Result.ok(shop);}

缓存击穿

也叫热点key问题,一个被高并发访问且业务复杂的key突然失效了,无数的请求瞬间给数据库带来的巨大冲击
在这里插入图片描述
解决方案: 互斥锁 逻辑过期

在这里插入图片描述
在这里插入图片描述
互斥锁思路:
在这里插入图片描述
查询缓存的时候,未命中需要获取锁 代码ShopServiceImpl

@Override
public Result queryById(Long id) {//1 redis中查询商户缓存String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);//2 判断是否存在if(StrUtil.isNotBlank(shopJson)){//3存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}if(shopJson!=null){return Result.fail("店铺不存在");}Shop shop = null;String lockKey = "lock.id:" + id;try {//代码到这里说明没有命中缓存,那么就可以获取锁了boolean isLock = tryLock(lockKey);// 如果没有拿到锁,则等待一会,递归执行代码if(!isLock){Thread.sleep(100);queryById(id);}//获取锁成功//4 不存在根据id去数据库查询shop = this.getById(id);//5 数据库也不存在,返回错误if(shop==null){// 空值写入redis中redisTemplate.opsForValue().set("cache.shop:" + id,"",3, TimeUnit.MINUTES);return Result.fail("店铺不存在");}//6 存在则写入redis中redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);} catch (InterruptedException e) {e.printStackTrace();} finally {unlock(lockKey);}//7 返回return Result.ok(shop);
}// 获取锁
private boolean tryLock(String key){Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);
}
//释放锁
private void unlock(String key){redisTemplate.delete(key);
}

缓存雪崩

同一时间段内,大量的缓存key失效或者redis宕机,到时大量的请求到达数据库,带来巨大的压力。
在这里插入图片描述
解决方案

  • 给key设置随机的TTL(有效时间)
  • 集群方案防止宕机不可用

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

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

相关文章

大数据 - Hadoop系列《五》- HDFS文件块大小及小文件问题

系列文章: 大数据- Hadoop入门-CSDN博客 大数据 - Hadoop系列《二》- Hadoop组成-CSDN博客 大数据 - Hadoop系列《三》- HDFS(分布式文件系统)概述_大量小文件的存储使用什么分布式文件系统-CSDN博客 大数据 - Hadoop系列《三》- MapRedu…

JMeter基础用法和测试WebSocket请求

目录 JMeter websocket插件安装测试接口的编写添加测试线程组创建取样器创建WebSocket连接创建循环控制器创建WebSocket request-response Sampler创建固定定时器 正则匹配上一个请求的数据做为当前请求参数正则编写使用匹配值 CSV文件读取参数添加汇总报告和结果树 JMeter web…

PyCharm中出现Microsoft Defender配置建议

原因 Windows安全中心的病毒和威胁防护会自动扫描电脑中的文件夹,我们的项目文件夹和IDE文件夹也会被扫描,而PyCharm认为这会降低IDE性能。 解决方法 直接点击提示框里的自动。 或是手动给扫描添加排除项,步骤如下: 1、先打开…

基于SSM 旅游平台的设计与实现

基于SSM 旅游平台的设计与实现 获取源码——》哔站搜:计算机专业毕设大全 获取源码——》哔站搜:计算机专业毕设大全 源码获取——》可以私信

ESP8266 WiFi物联网智能插座—上位机软件实现

1、软件架构 上位机主要作为下位机数据上传服务端以及节点调试的控制端,可以等效认为是专属版本调试工具。针对智能插座协议,对于下位机进行可视化监测和管理。 软件技术架构如下,主要为针对 Windows 的PC 端应用程序,采用WPF以及…

Spring Boot单元测试全指南:使用Mockito和AssertJ

🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…

使用hping3网络工具构造TCP/IP数据包和进行DDos攻击

1 概述 hping3是一个强大的命令行工具,用于生成、发送和解析TCP/IP协议的数据包。它是开源的网络安全工具,由Salvatore Sanfilippo开发,主要应用于网络审计、安全测试和故障排查等领域。hping3不仅可以作为普通的网络连通性检测工具&#xf…

基于YOLOV8+Pyqt5光伏太阳能电池板目标检测系统

1、YOLOV8算法 YOLOv8 是当前效果较好的目标检测 算法,它的核心网络来源于 DarkNet-53,该网络初次在 YOLOv3[11] 中被引入,并深受 ResNet[12] 的影响。DarkNet-53 使用了残差机制,并连续添加了卷积模块来加强其功能性。 这 53 层…

VBA高级应用30例应用2:MouseMove鼠标左键按下并移动鼠标事件

《VBA高级应用30例》(版权10178985),是我推出的第十套教程,教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开,这套教程案例与理论结合,紧贴“实战”,并做“战术总结”,以…

稀碎从零算法笔记Day35-LeetCode:字典序的第K小数字

要考虑完结《稀碎从零》系列了哈哈哈 这道题和【LC.42 接雨水】,我愿称之为【笔试界的颜良&文丑】 题型:字典树、前缀获取、数组、树的先序遍历 链接:440. 字典序的第K小数字 - 力扣(LeetCode) 来源&#xff1…

(文章复现)考虑分布式电源不确定性的配电网鲁棒动态重构

参考文献: [1]徐俊俊,吴在军,周力,等.考虑分布式电源不确定性的配电网鲁棒动态重构[J].中国电机工程学报,2018,38(16):4715-47254976. 1.摘要 间歇性分布式电源并网使得配电网网络重构过程需要考虑更多的不确定因素。在利用仿射数对分布式电源出力的不确定性进行合…

鸿蒙HarmonyOS应用开发之HID DDK开发指导

场景介绍 HID DDK(HID Driver Develop Kit)是为开发者提供的HID设备驱动程序开发套件,支持开发者基于用户态,在应用层开发HID设备驱动。提供了一系列主机侧访问设备的接口,包括创建设备、向设备发送事件、销毁设备。 …

负载均衡策略和技术的基本指南

什么是负载均衡器? 负载均衡器将传入的网络流量分布到多个服务器上,以确保没有单个服务器承受过多的负载。通过有效地传播请求,它们提高了应用程序的容量和可靠性。 下面是一些使用负载均衡器的常见场景: 高并发流量:当应用程序面临大量用户请求时,负载均衡器可以将流量分…

【4】单链表(有虚拟头节点)

【4】单链表(有虚拟头节点) 1、虚拟头节点2、构造方法3、node(int index) 返回索引位置的节点4、添加5、删除6、ArrayList 复杂度分析(1) 复杂度分析(2) 数组的随机访问(3) 动态数组 add(E element) 复杂度分析(4) 动态数组的缩容(5) 复杂度震荡 7、单链…

七、函数的使用方法

函数的调用 nameinput()#输入参数并赋值name print(name)#d打印name 格式:返回值函数名(参数) def get_sum(n):#形式参数计算累加和:param n::return: sumsum0for i in range(1,n1):sumiprint…

9.Python类与对象

1 面向对象 类和对象都是面向对象中的重要概念。面向对象是一种编程思想, 即按照真实世界的思维方式构建软件系统。 例如,在真实世界的校园里有学生和老师,学生有学号、姓名、所 在班级等属性(数据),还有…

【苹果MAC】苹果电脑 LOGI罗技鼠标设置左右切换全屏页面快捷键

首先键盘设置->键盘快捷键 调度中心 设置 f1 f2 为移动一个空间(就可以快捷移动了) 想要鼠标直接控制,就需要下载官方驱动,来设置按键快捷键,触发 F1 F2 安装 LOGI OPTIONS Logi Options 是一款功能强大且便于使用…

前端虚拟滚动列表 vue虚拟列表

前端虚拟滚动列表 在大型的企业级项目中经常要渲染大量的数据,这种长列表是一个很普遍的场景,当列表内容越来越多就会导致页面滑动卡顿、白屏、数据渲染较慢的问题;大数据量列表性能优化,减少真实dom的渲染 看图:绿色…

设计模式之工厂方法模式精讲

工厂方法模式又叫虚拟构造函数(Virtual Constructor)模式或者多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建性工作推迟到子类中。 工厂模式可以分为简单工厂…

第六十三回 呼延灼月夜赚关胜 宋公明雪天擒索超-大模型BERT、ERNIE、GPT和GLM的前世今生

神行太保戴宗报信,关胜人马直奔梁上泊,请宋江早早收兵,解梁山之难。宋江派了花荣到飞虎峪左边埋伏,林冲到右边埋伏,再叫呼延灼带着凌振,在离城十里附近布置了火炮,然后才令大军撤退。 李成闻达…