使用Redis实现业务信息缓存(缓存详解,缓存更新策略,缓存三大问题)-更新中
一、什么是缓存?
缓存是一种高效的数据存储方式,它通过将数据保存在内存中来提供快速的读写访问。这种机制特别适用于需要高速数据访问的应用场景,如网站、应用程序和服务。在处理大量数据和高并发请求时, 缓存能显著提高性能和用户体验。
Redis就是一款常用的缓存中间件。
二、如何在业务中结合Redis进行缓存(代码模版)?
1.基本步骤
在业务中结合Redis进行缓存主要有以下步骤:
(1)根据key到redis中查找对应值
(2)若查找到,则直接返回。若redis中没有,则在数据库中进行查找
(3)数据库查找完毕后,先存储查找到的数据到redis中,便于下次查找同样数据的时候,可以直接从redis中获取,不用走数据库,减轻数据库的压力
(4)最后将数据进行返回即可
2.代码模版
这里以查找商铺信息为例,给出结合redis进行商铺信息缓存的代码:
(1)Controller层:
/*** 根据id查询商铺信息* @param id 商铺id* @return 商铺详情数据*/@GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {return shopService.queryById(id);}
(2)Service层:
@AutowiredStringRedisTemplate stringRedisTemplate;/*** 根据id查询商铺信息* @param id* @return*/@Overridepublic Result queryById(Long id) {//1.从redis查询商铺缓存String key = RedisConstants.CACHE_SHOP_KEY + id;String shopFromRedis = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if(!StringUtils.isEmpty(shopFromRedis)){//3.redis存在此商铺,返回结果Shop shop = JSONUtil.toBean(shopFromRedis, Shop.class);return Result.ok(shop);}//4.不存在,到数据库中去查询Shop shop = getById(id);//5.数据库不存在,返回错误if(shop == null){return Result.fail("店铺不存在");}//6.数据库存在,写入redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);//7.返回结果return Result.ok(shop);}
三、缓存更新策略
1.三种缓存更新策略
缓存更新策略主要有:内存淘汰,超时剔除和主动更新这三种。
1.内存淘汰:
简单来说就是Redis根据其内存大小,其淘汰策略(如:键值对的访问频率)等,对键值对进行淘汰。 可以对redis进行配置(如:设置redis内存大小),来控制其内存淘汰。这种方法一般由redis自主控制,因此其一致性也比较差。
2.超时剔除:
简单来说,就是在向redis存入键值对的时候,为这个键值对赋予一个TTL(超时时间),如果超过这个时间,redis就会将这个键值对进行删除。其一致性相较于内存淘汰策略会好一些。
3.主动更新:
也就是在修改数据库的时候对缓存也进行修改。这种方法一致性相较于前两种会好很多,但是需要由程序员自主编码进行控制,会复杂一些。
一般使用主动更新策略为主,结合超时剔除作为兜底,来实现缓存的更新。
2.主动更新详解
2.1.三种主动更新策略
(1)Cache Aside Pattern:
由缓存的调用者,在更新数据库的同时更新缓存
(2)Read/Write Through Pattern:
缓存与数据库整合为一个服务,由服务维护一致性,调用者调用该服务,无需关心缓存一致性问题。但这种方式较为复杂,市面上提供这种服务的框架较少。
(3)Write Behind Caching Pattern:
调用者只操作缓存,由其他线程异步的将缓存的数据持久化到数据库,保证最终一致。这种方式的所有更新操作都是在缓存中进行的,其他线程会按照某种规则(定时/缓存占用达到一定比例)把数据持久化到数据库中,虽然可以减少对数据库的更新操作,但是这种方法也存在一定的弊端:
最新的数据都存储在内存中,一旦redis出现故障,数据会全部丢失,易失性高。
加剧服务器的压力,因为每一个请求都要监视是否需要将缓存持久化到数据库。
总结:
在开发中,一般使用Cache Aside Patter策略,由缓存的调用者,在更新数据库的同时更新缓存。
2.2 Cache Aside Pattern
2.2.1 操作缓存和数据库时三个需要考虑的问题
1.删除缓存还是更新缓存?
- 更新缓存:每次更新数据库都更新缓存,无效写操作较多 ❌
如果更新数据库的次数多,而读取的次数较少,则每次更新时,都会增加无效的更新缓存操作
- 删除缓存:更新数据库时让缓存失效,查询时再更新缓存 ✔️
2.如何保证缓存与数据库的操作的同时成功或失败?
- 单体系统:将缓存与数据库操作放在一个事务
- 分布式系统:利用TCC等分布式事务方案
3.先操作缓存还是先操作数据库?
对缓存的操作比较快,而对数据库的更新操作速度通常会比较慢。
因此,先写数据库在删除缓存,也即先执行慢的操作B,再执行的操作A。这样引发线程安全的线程必须在操作A执行的那段时间达到,相较于先A后B的方式,引发线程安全的概率会小很多。
3.缓存更新策略最终方案
3.1 方案
- 低一致性需求:使用Redis自带的内存淘汰机制
- 高一致性需求:主动更新,并以超时剔除作为兜底方案
读操作:
- 缓存命中则直接返回
- 缓存未命中则查询数据库,并写入缓存,设定超时时间
写操作:
- 先写数据库,然后再删除缓存
- 要确保数据库与缓存操作的原子性
3.2 实现代码:
这里以更新商铺信息功能为例:
/*** 更新店铺信息* @param shop* @return*/@Override@Transactional//保证更新数据库和删除缓存同时成功public Result updateShop(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不能为空");}//1.写入数据库updateById(shop);//2.删除缓存String key = RedisConstants.CACHE_SHOP_KEY + id;stringRedisTemplate.delete(key);return Result.ok();}
四、缓存三大问题(穿透,雪崩、击穿)
1、缓存穿透
1.1
1.2 参考代码
@AutowiredStringRedisTemplate stringRedisTemplate;/*** 根据id查询商铺信息* @param id* @return*/@Overridepublic Result queryById(Long id) {//1.从redis查询商铺缓存String key = RedisConstants.CACHE_SHOP_KEY + id;String shopFromRedis = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if(!StringUtils.isEmpty(shopFromRedis)){//shopFromRedis不为 null && 不为""的时候为真//3.redis存在此商铺,返回结果Shop shop = JSONUtil.toBean(shopFromRedis, Shop.class);return Result.ok(shop);}if(shopFromRedis != null){//shopFromRedis 为 “”//这个数据在缓存和数据库中不存在,由于之前存储过 “”,直接返回,避免缓存穿透return Result.fail("店铺不存在");}//4.不存在,到数据库中去查询Shop shop = getById(id);//5.数据库不存在,返回错误if(shop == null){//避免缓存穿透,将空值写入redisstringRedisTemplate.opsForValue().set(key,"",RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在");}//6.数据库存在,写入redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);//7.返回结果return Result.ok(shop);}
相关文章:
使用Redis实现业务信息缓存(缓存详解,缓存更新策略,缓存三大问题)-更新中
一、什么是缓存? 缓存是一种高效的数据存储方式,它通过将数据保存在内存中来提供快速的读写访问。这种机制特别适用于需要高速数据访问的应用场景,如网站、应用程序和服务。在处理大量数据和高并发请求时, 缓存能显著提高性能和用…...
Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南
引言 随着人工智能技术的飞速发展,各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力,受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具,能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…...
1.2 变革里程碑:Transformer 的崛起
变革里程碑:Transformer 的崛起 一、架构革命的核心驱动力 #mermaid-svg-hsXnwHI0wO2qZaqb {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}#mermaid-svg-hsXnwHI0wO2qZaqb .error-icon{fill:#552222;}#mermaid-sv…...
SpringBoot速成(八)登录实战:未登录不能访问 P5-P8
1.登录 package com.itheima.springbootconfigfile.controller;import com.itheima.springbootconfigfile.pojo.Result; import com.itheima.springbootconfigfile.pojo.User; import com.itheima.springbootconfigfile.service.UserService;import com.itheima.springbootco…...
[Unity角色控制专题] 详细说明如何使用Character Controller配合脚本实现类似MC的第一人称控制(仅移动与视角摇晃)
关于角色控制器的基本用法我就不做介绍了,请自行查看相关文档: Unity - Manual: Character Controller component reference 本文用到了三角函数和插值函数,非常简单,如有疑问请查询以下文章: Unity中的数学 之 Mathf_uni…...
2025_2_9 C语言中队列
1.队列(先进先出) 队列也是一种受限制的线性结构 它只能在一端添加元素,在另一端访问,删除元素 (队首插入,队尾删除) 因为链表实现没有数组实现快,所以队列大多数是用数组实现的 q…...
(原创,可用)SSH实现内外网安全穿透(安全不怕防火墙)
目前有A、B终端和一台服务器,A、B机器不能直接访问,服务器不能直接访问A、B终端但是A、B终端可以访问服务器,这个场景很像我们有一台电脑在单位内网,外机器想访问内网系统,可能大家目前想到的就是frp之类穿透工具&…...
mysql安装starting the server报错
win10家庭版无法启动服务的,先不要退出,返回上一栏,然后通过电脑搜索栏输入服务两个字,在里面找到mysql80,右键属性-登录,登录身份切换为本地系统就行了...
设计高效的测试用例:从需求到验证
在现代软件开发过程中,测试用例的设计一直是质量保证(QA)环节的核心。有效的测试用例不仅能够帮助发现潜在缺陷,提升软件质量,还能降低后期修复成本,提高开发效率。尽管如此,如何从需求出发&…...
【阅读笔记】信息熵自动曝光An Automatic Exposure Algorithm Based on Information Entropy
一、算法背景 信息熵作为衡量图像信息量的重要指标,能够反映图像的细节丰富程度。通过基于信息熵的自动曝光算法,可以自动调整曝光时间,使图像包含更多信息,从而提高图像质量。 灰度直方图在各个灰度值上分布越均匀,…...
Dockerfile 文件详解
在平常的开发工作中,我们经常需要部署项目,一个项目开发完成后,使用 Docker 方式部署,那么首先得构造镜像,构造镜像最主要的就是 Dockerfile 文件的编写,今天简单来总结下 Dockerfile 文件的编写以及有哪些…...
模型压缩 --学习记录2
模型压缩 --学习记录2 如何找到更好的权衡方式(模型量化)方法一:寻找更好的 range方法二:寻找更好的 X-fp32(浮点数)方法三:寻找更好的 scale 和 zp方法四:寻找更好的 roundPTQ 后训练量化(离线量化)QAT 量化感知训练(在线量化)量化为什么会带来加速?三、模型稀疏技…...
JVM常见命令
引言 掌握JVM是属于Java程序员的必修课,对线程的掌控,对内存的把控,所以了解JVM常见命令可以帮助我们快速了解虚拟机的详细数据 命令 1. java 这是最基础的命令,用于启动一个 Java 应用程序。 java -cp /path/to/your/class…...
ASP.NET Core托管服务
目录 托管服务的异常问题 托管服务中使用DI 托管服务案例:数据的定时导出 场景,代码运行在后台。比如服务器启动的时候在后台预先加载数据到缓存,每天凌晨3点把数据导出到备份数据库,每隔5秒钟在两张表之间同步一次数据。托管服…...
模型压缩中的四大核心技术 —— 量化、剪枝、知识蒸馏和二值化
一、量化 (Quantization) 量化的目标在于将原始以 32 位浮点数表示的模型参数和中间激活,转换为低精度(如 FP16、INT8、甚至更低位宽)的数值表示,从而在减少模型存储占用和内存带宽的同时,加速推理运算,特别适用于移动、嵌入式和边缘计算场景。 1.1 概念与目标 基本思想…...
C++:类和对象初识
C:类和对象初识 前言类的引入与定义引入定义类的两种定义方法1. 声明和定义全部放在类体中2. 声明和定义分离式 类的成员变量命名规则 类的访问限定符及封装访问限定符封装 类的作用域与实例化类的作用域类实例化实例化方式: 类对象模型类对象的大小存储…...
01-SDRAM控制器的设计——案例总概述
本教程重点▷▷▷ 存储器简介。 介绍 SDRAM 的工作原理。 详细讲解SDRAM 控制的Verilog 实现方法。 PLL IP和FIFO IP 的调用,计数器设计,按键边沿捕获,数码管控制。 完成SDRAM控制器应用的完整案例。 Signal Tap 调试方法。 准备工作▷…...
笔记:蓝桥杯python搜索(3-2)——DFS剪支和记忆化搜索
目录 一、DFS剪支 二、例题 P2942 数字王国之军训军队 P3075 特殊的多边形 三、记忆化搜索 四、例题 例题 P3820 混境之地 P216 地宫取宝 一、DFS剪支 在搜索过程中,如果需要完全遍历所有情况可能需要很多时间在搜索到某种状态时,根据当前状态判断…...
处理数据及其选择关键列进行一次聚类
1. 数据加载与初步处理 # 文件路径 file_path ../data/all_database_result.csv# 读取CSV文件到DataFrame df pd.read_csv(file_path)# 选择特定的特征列 selected_features [Q10, Q12, Q13, Q14]# 缺失值处理:这里简单地删除含有任何缺失值的行 df.dropna(subse…...
Qt 支持的动画格式对比,Lottie/APNG/GIF/WEBP
Qt版本:6.7.2 , QML 一,Lottie 在qml中使用LottieAnimation即可,但有三个问题: 1.动画加载中报错: 如果图片(.json)本身存在不支持的effect 或shape type等,效果并不好:…...
FaceFusion如何设置公开链接和端口
有时候我们想在局域网内的其他设备上使用 FaceFusion,这时候需要设置公开链接和端口。 当你运行 FaceFusion 的时候,会发现有这样的一段提示: To create a public link, set shareTrue in launch().但是这个提示是错的,如果你查…...
【安当产品应用案例100集】037-强化OpenVPN安全防线的卓越之选——安当ASP身份认证系统
在当前数字化时代,网络安全已成为企业发展的重要组成部分。对于使用OpenVPN的企业而言,确保远程访问的安全性尤为重要。安当ASP身份认证系统凭借其强大的功能和便捷的集成方式,为OpenVPN的二次登录认证提供了理想的解决方案,特别是…...
RK3568实战项目(六)--开发工具介绍
目录 一、引言 二、开发工具 ------>2.1、trust_merger ------>2.2、boot_merger ------>2.3、loaderimage ------>2.4、resource_tool ------>2.5、mkimage ------>2.6、mkbootimg ------>2.7、unpack_bootimg ------>2.8、repack-bootimg …...
01.02、判定是否互为字符重排
01.02、[简单] 判定是否互为字符重排 1、题目描述 给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 在这道题中,我们的任务是判断两个字符串 s1 和 s2 是…...
尝试一下,交互式的三维计算python库,py3d
py3d是一个我开发的三维计算python库,目前不定期在PYPI上发版,可以通过pip直接安装 pip install py3d 开发这个库主要可视化是想把自己在工作中常用的三维方法汇总积累下来,不必每次重新造轮子。其实现成的python库也有很多,例如…...
DeepSeek-R1模型的数学原理(说人话)
文章目录 1、什么是GRPO2、数学原理3、比喻4、流程总结 🍃作者介绍:双非本科大四网络工程专业在读,阿里云专家博主,前三年专注于Java领域学习,擅长web应用开发,目前已转行人工智能领域。 🦅个人…...
安宝特方案 | AR助力制造业安全巡检智能化革命!
引言: 在制造业中,传统巡检常面临流程繁琐、质量波动、数据难以追溯等问题。安宝特AR工作流程标准化解决方案,通过增强现实AR技术,重塑制造业安全巡检模式,以标准化作业流程为核心,全面提升效率、质量与…...
DeepSeek和ChatGPT的对比
最近DeepSeek大放异彩,两者之间有什么差异呢?根据了解到的信息,简单做了一个对比。 DeepSeek 和 ChatGPT 是两种不同的自然语言处理(NLP)模型架构,尽管它们都基于 Transformer 架构,但在设计目标…...
AJAX项目——数据管理平台
黑马程序员视频地址: 黑马程序员——数据管理平台 前言 功能: 1.登录和权限判断 2.查看文章内容列表(筛选,分页) 3.编辑文章(数据回显) 4.删除文章 5.发布文章(图片上传࿰…...
神经网络常见激活函数 5-PReLU函数
文章目录 PReLU函数导函数函数和导函数图像优缺点pytorch中的PReLU函数tensorflow 中的PReLU函数 PReLU 参数化修正线性单元:Parametric ReLU 函数导函数 PReLU函数 P R e L U { x x > 0 α x x < 0 ( α 是可训练参数 ) \rm PReLU \left\{ \begin{array}{} x \qua…...
艾蒿染色体水平基因组-文献精读111
A chromosome-scale genome assembly of Artemisia argyi reveals unbiased subgenome evolution and key contributions of gene duplication to volatile terpenoid diversity 一项关于艾蒿(Artemisia argyi)的染色体尺度基因组组装揭示了无偏的亚基因…...
EB生成配置的过程
EB Tresos Studio,简称EB,通过图形化的模式进行配置生成,并根据选项配置生成配置代码,即 MCAL 层各个模块的配置参数。 在 MCAL 代码中,分为静态代码和配置代码。静态代码,就是 AUTOSAR 规范内容,包含对硬件的封装以及标准化接口的封装;配置代码一般用于配置初始化结构…...
使用Docker + Ollama在Ubuntu中部署deepseek
1、安装docker 这里建议用docker来部署,方便简单 安装教程需要自己找详细的,会用到跳过 如果你没有安装 Docker,可以按照以下步骤安装: sudo apt update sudo apt install apt-transport-https ca-certificates curl software-p…...
NFT Insider #168:The Sandbox 推出新春{金蛇礼服}套装;胖企鹅合作 LINE Minini
引言:NFT Insider 由 NFT 收藏组织 WHALE Members、BeepCrypto 联合出品, 浓缩每周 NFT 新闻,为大家带来关于 NFT 最全面、最新鲜、最有价值的讯息。每期周报将从 NFT 市场数据,艺术新闻类,游戏新闻类,虚拟…...
字符串高频算法:无重复字符的最长子串
题目 3. 无重复字符的最长子串 - 力扣(LeetCode) 解题思路 思路 方法: 滑动窗口 [!简单思路] [^1]以示例一中的字符串 abcabcbb 为例,找出从每一个字符开始的,不包含重复字符的最长子串,其中最长的那个字符串即为答…...
集成学习(一):从理论到实战(附代码)
一、引言 在机器学习领域,打造一个独立、强大的算法是解决问题的关键。然而,集成学习提供了一种不同的视角:通过组合多个“弱”学习器来创建一个更强大的模型。本文探讨集成学习的思想、方法及其应用。 二、机器学习 vs 集成学习思想 传统…...
本地部署DeepSeek-R1模型(新手保姆教程)
背景 最近deepseek太火了,无数的媒体都在报道,很多人争相着想本地部署试验一下。本文就简单教学一下,怎么本地部署。 首先大家要知道,使用deepseek有三种方式: 1.网页端或者是手机app直接使用 2.使用代码调用API …...
轻松理解CSS中的float浮动元素
1.float:left,float:right可以让元素脱离原始文档流,也就是所谓的“浮动”,可以理解为元素漂浮在原本所占位置的上空,意思是元素漂浮起来了,不占原始文档流的空间。但是,别的元素可以感知到浮动元素的存在&…...
SOME/IP--协议英文原文讲解5
前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 这一章节…...
如何优化频繁跳槽后的简历?
大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | A…...
存储异常导致的Oracle重大生产故障
📢📢📢📣📣📣 作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…...
从家庭IP到全球网络资源的无缝连接:Cliproxy的专业解决方案
数字化时代,家庭IP作为个人或家庭接入互联网的门户,其重要性日益凸显。然而,要实现从家庭IP到全球网络资源的无缝连接,并享受高效、安全、稳定的网络访问体验,往往需要借助专业的代理服务。Cliproxy,作为业…...
java项目之金华学校社团管理系统源码(ssm+mysql)
项目简介 金华学校社团管理系统实现了以下功能: 金华学校社团管理系统的主要使用者管理员对系统用户、公告信息进行管理。对社团信息进行管理,审核报名,统计社团报名结果等。学生维护个人信息,查看本校的社团信息,对…...
链表(LinkedList) 1
上期内容我们讲述了顺序表,知道了顺序表的底层是一段连续的空间进行存储(数组),在插入元素或者删除元素需要将顺序表中的元素整体移动,时间复杂度是O(n),效率比较低。因此,在Java的集合结构中又引入了链表来解决这一问…...
一、OSG学习笔记-编译开发环境
一、准备工作 1、osg3.6.4源码下载; openscenegraph/OpenSceneGraph at OpenSceneGraph-3.6.4 还有osg中所依赖的第三方库 2、cmake 下载安装好 3、Visual Studio 2019下载安装好 二、cmake 编译构建项目 这里下方1,2,两个先点击1&am…...
【Redis】Linux、Windows、Docker 环境下部署 Redis
一、Linux环境部署Redis 1、卸载 # 查看 Redis 是否还在运行 [appuserlocalhost redis]$ ps -ef|grep redis appuser 135694 125912 0 14:24 pts/1 00:00:00 ./bin/redis-server *:6379 appuser 135731 125912 0 14:24 pts/1 00:00:00 grep --colorauto redis# 停止…...
OSPF基础(3):区域划分
OSPF的区域划分 1、区域产生背景 路由器在同一个区域中泛洪LSA。为了确保每台路由器都拥有对网络拓扑的一致认知,LSDB需要在区域内进行同步。OSPF域如果仅有一个区域,随着网络规模越来越大,OSPF路由器的数量越来越多,这将导致诸…...
第436场周赛:按对角线进行矩阵排序、将元素分配给有约束条件的组、统计可以被最后一个数位整除的子字符串数目、最大化游戏分数的最小值
Q1、按对角线进行矩阵排序 1、题目描述 给你一个大小为 n x n 的整数方阵 grid。返回一个经过如下调整的矩阵: 左下角三角形(包括中间对角线)的对角线按 非递增顺序 排序。右上角三角形 的对角线按 非递减顺序 排序。 2、解题思路 遍历所…...
DeepSeek vs. ChatGPT:不同的诞生时间,对人工智能发展的不同影响
DeepSeek vs. ChatGPT:不同的诞生时间,对人工智能发展的不同影响 ChatGPT 和 DeepSeek 诞生于不同的时间节点,代表了人工智能不同阶段的发展方向。它们在技术、应用以及对AI发展趋势的影响方面各有侧重。 1. 诞生时间与背景 ChatGPT&#x…...
chrome-base 如何实现一个BindOnce
考虑一个问题: worker_thread.task_runner()->PostDelayedTask(FROM_HERE, base::BindOnce(&Ref::Foo, ref, 1), base::Milliseconds(1000)); BindOnce 是如何实现的呢? 翻看源码:base\functional\bind.h 写的 非常简洁 // Bind a…...