黑马点评-05缓存穿透问题及其解决方案,缓存空字符串或使用布隆过滤器

缓存穿透问题(缓存空)

缓存穿透的解决方案

缓存穿透(数据穿透缓存直击数据库): 缓存穿透是指客户端请求访问缓存中和数据库中都不存在的数据,此时缓存永远不会生效并且用户的请求都会打到数据库

  • 数据库能够承载的并发不如Redis这么高,如果大量的请求同时访问这种不存在的数据,这些请求就都会访问到数据库就会造成数据库瘫痪

缓存穿透的解决方案有哪些

  • 缓存null值

  • 布隆过滤

  • 增强id的复杂度,这样用户就不知道缓存中和数据库中不存在的数据有哪些

  • 做好数据的基础格式校验

  • 加强用户权限校验

  • 做好热点参数的限流

缓存空对象

即使访问的数据在数据库中不存在也要把这个数据缓存到redis中去,这样用户下次再访问这个不存在的数据时就能在redis中找到这个数据所以不会进入到缓存

  • 优点: 实现简单且维护方便
  • 缺点: 造成额外的内存消耗(可以设置一个TTL), 可能造成数据库和缓存短期的数据不一致(只有TTL到期时才能更新缓存)

在这里插入图片描述

布隆过滤(哈希思想)

布隆过滤器其实采用的是哈希思想,使用一个庞大的二进制数组通过哈希算法把数据库中的数据对应hash值转换成二级制位保存起来

  • 只有布隆过滤器判断要查询的数据存在时才会放行(如果发生哈希碰撞,布隆认为存在的数据可能不存在),不存在则直接返回(一定不存在)

  • 这个请求会去访问redis,哪怕此时redis中的数据过期了,但是数据库中一定存在这个数据,在数据库中查询出来这个数据后,再将其放入到redis中

  • 优点: 内存占用较少且没有多余key

  • 缺点: 实现复杂且存在误判可能(哈希算法可能存在哈希冲突)

在这里插入图片描述

解决商品查询的缓存穿透

如果查询的数据在数据库中找不到不是返回404,而是把这个数据库中不存在的数据也写入到Redis中并且将value设置为空字符串同时设置一个较短的TTL

  • 再次发起同样的查询请求时,肯定会命中缓存,但是由于value是空字符串会,表示查询的是不存在的数据,直接返回一个错误信息,避免了再次查询数据库的操作

在这里插入图片描述

// 设置缓存空字符串的超时时间
public static final Long CACHE_NULL_TTL = 2L;
@Override
public Result queryById(Long id) {// 先从Redis中查询对应的店铺缓存信息,这里的常量值是固定店铺的前缀+查询店铺的idString shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 如果在Redis中查询到了店铺信息,并且店铺的信息不是空字符串则转为Shop类型直接返回,""和null以及"/t/n(换行)"都会判定为空即返回falseif (StrUtil.isNotBlank(shopJson)) {Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 如果缓存的店铺信息是空字符串(shopjson == "")即我们缓存的空数据,返回一个错误信息if (shopjson != null) { return Result.fail("店铺不存在!!");}// 如果没有命中并且店铺信息不是空字符串即shopjson等于null则去数据库中根据查Id查询店铺信息Shop shop = getById(id);// 在数据库中查询不到店铺,把这个不存在的数据也写入到Redis中并且将value设置为空字符串同时设置一个较短的TTL(如2分钟)if (shop == null) {stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在!!");}// 查到了则将店铺对象转为json字符串存入redis同时设置TTLString jsonStr = JSONUtil.toJsonStr(shop);stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, jsonStr, CACHE_SHOP_TTL, TimeUnit.MINUTES);// 最终把查询到的商户信息返回给前端return Result.ok(shop);
}

单独实现解决缓存穿透的方法queryWithPassThrough,在该方法中如果查到店铺信息返回shop查不到则返回null,最后在queryById中做统一判断返回结果类

@Override
public Result queryById(Long id) {// 测试缓存穿透Shop shop = queryWithPassThrough(id);// 如果shop等于null,表示数据库中对应店铺不存在或者缓存的店铺信息是空字符串if (shop == null) {return Result.fail("店铺不存在!!");}// shop不等于null,把查询到的商户信息返回给前端return Result.ok(shop);
}@Override
public Result queryWithPassThrough(Long id) {// 先从Redis中查询对应的店铺缓存信息,这里的常量值是固定的店铺前缀+查询店铺的IdString shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 如果在Redis中查询到了店铺信息,并且店铺的信息不是空字符串则转为Shop类型直接返回,""和null以及"/t/n(换行)"都会判定为空即返回falseif (StrUtil.isNotBlank(shopJson)) {Shop shop = JSONUtil.toBean(shopJson, Shop.class);return shop;}// 如果缓存的店铺信息是空字符串(shopjson == "")即我们缓存的空数据,返回nullif (shopjson != null) { return null;}// 如果没有命中并且店铺信息不是空字符串即shopjson等于null则去数据库中根据查Id查询店铺信息Shop shop = getById(id);// 在数据库中查询不到店铺,把这个不存在的数据也写入到Redis中并且将value设置为空字符串同时设置一个较短的TTL(如2分钟)if (shop == null) {stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}// 查到了则将店铺对象转为json字符串存入redis同时设置TTLString jsonStr = JSONUtil.toJsonStr(shop);stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, jsonStr, CACHE_SHOP_TTL, TimeUnit.MINUTES);// 最终把查询到的商户信息返回给前端return shop;
}

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

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

相关文章

vue使用localstorage超出限制解决方法

最近在项目中,遇到一个报错,QuotaExceededError: The quota has been exceeded。如图: 搜索了一下,结合项目代码,得到的结论是localStorage超出5M限制了,项目中使用了vuex-persistedstate插件,…

Redis-双写一致性

双写一致性 双写一致性解决方案延迟双删(有脏数据的风险)分布式锁(强一致性,性能比较低)异步通知(保证数据的最终一致性,高并发情况下会出现短暂的不一致情况) 双写一致性 当修改了数…

10_10C++

X-mid #include <iostream> using namespace std; class Kun {//算术运算符friend const Kun operator(const Kun &k1,const Kun &k2);friend const Kun operator-(const Kun &k1,const Kun &k2);friend const Kun operator*(const Kun &k1,const Ku…

[nltk_data] Error loading stopwords: <urlopen error [WinError 10054]

报错提示&#xff1a; >>> import nltk >>> nltk.download(stopwords) 按照提示执行后 [nltk_data] Error loading stopwords: <urlopen error [WinError 10054] 找到路径C:\\Users\\EDY\\nltk_data&#xff0c;如果没有nltk_data文件夹&#xff0c;在…

【算法|双指针系列No.4】leetcode11. 盛最多水的容器

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

解决:yarn 无法加载文件 “C:\Users\XXXXX\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本“ 的问题

1、问题描述&#xff1a; 报错的整体代码为&#xff1a; yarn : 无法加载文件 C:\Users\admin\AppData\Roaming\npm\yarn.ps1&#xff0c;因为在此系统上禁止运行脚本 // 整体的报错代码为 &#xff1a; yarn : 无法加载文件 C:\Users\admin\AppData\Roaming\npm\yarn.ps1&…

vue3学习(一)---新特性

文章目录 vue3和vue2的区别重写双向数据绑定优化Vdom性能瓶颈patch flag 优化静态树 FragmentTree shaking组合式API写法 vue3和vue2的区别 重写双向数据绑定 vue2 基于Object.defineProperty()实现vue3 基于Proxy proxy与Object.defineProperty(obj, prop, desc)方式相比有以…

[idekCTF 2022]Paywall - LFI+伪协议+filter_chain

[idekCTF 2022]Paywall 一、解题流程&#xff08;一&#xff09;、分析&#xff08;二&#xff09;、解题 二、思考总结 一、解题流程 &#xff08;一&#xff09;、分析 点击source可以看到源码&#xff0c;其中关键部分&#xff1a;if (isset($_GET[p])) {$article_content…

阶段六-Day02-Maven

一、学习Maven 使用Maven创建Web项目&#xff0c;并部署到服务器。 二、Maven介绍及加载原理 1. 介绍 Maven是使用Java语言编写的基于项目对象模型&#xff08;POM&#xff09;的项目管理工具。开发者可以通过一小段描述信息来管理项目的构建、报告和文档。 使用Maven可以…

LabVIEW玩转魔方

LabVIEW玩转魔方 使用LabVIEW创建一个3D魔方&#xff0c;并找出解谜题的秘密&#xff0c;给朋友留下深刻深刻的印象。游戏中内置的机制使每张脸都能独立转动&#xff0c;从而混合颜色。要解决难题&#xff0c;每个面必须是相同的纯色 魔方的奥秘在于它的简单性和不可解性。这是…

uni-app:服务器端数据绘制echarts图标(renderjs解决手机端无法显示问题)

效果 代码 <template><view click"echarts.onClick" :prop"option" :change:prop"echarts.updateEcharts" id"echarts" class"echarts"></view> </template><script>export default {data()…

设计模式 - 迭代器模式

目录 一. 前言 二. 实现 三. 优缺点 一. 前言 迭代器模式是一种行为型设计模式&#xff0c;它提供了一种统一的方式来访问集合对象中的元素&#xff0c;而不暴露集合内部的表示方式。简单地说&#xff0c;就是将遍历集合的责任封装到一个单独的对象中&#xff0c;我们可以按…