黑马点评之缓存工具封装

发布时间:2026/9/2 6:15:28

黑马点评之缓存工具封装
1.1缓存工具的定位和选择方法1和方法3配对起来解决一些常见的缓存问题方法2和方法4配对起来是为了解决热点key的。1.2设置逻辑过期时间方法和设置TTL过期时间public class CacheClient { private StringRedisTemplate stringRedisTemplate; public CacheClient(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } public void set(String key, Object value, Long time, TimeUnit unit){ stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit); } public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){ //设置逻辑过期,把value封装到redisData对象里面去存就能诞生逻辑过期时间了 RedisData redisData new RedisData(); redisData.setData(value); redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); //plusSeconds是加上时间的unit是单位time是传进来的时间参数但是不能确定是秒所以需要用toSeconds去转一下 //写入Redis stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData),time,unit); }1.2.1设置TTL过期时间public void set(String key, Object value, Long time, TimeUnit unit){stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);}因为stringRedisTemplate要求的类型是string而传value的类型是Object所以需要把对象序列化为json字符串。1.2.2设置逻辑过期时间方法public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){//设置逻辑过期,把value封装到redisData对象里面去存就能诞生逻辑过期时间了RedisData redisData new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));//plusSeconds是加上时间的unit是单位time是传进来的时间参数但是不能确定是秒所以需要用toSeconds去转一下//写入RedisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData),time,unit);}1.3用缓存空值解决缓存击穿public R,ID R queryWithPassThrough( String keyPrefix, ID id, ClassR type, FunctionID,R dbFallback, Long time, TimeUnit unit){ String key CACHE_SHOP_KEY id;//把这个转为字符串方便使用前面标明cache shop 方便区分id //1.从redis查缓存 String shopJson stringRedisTemplate.opsForValue().get(key);//以店铺id做为key,这样就得到店铺的json字符串 //2.判断是否存在 if (StrUtil.isNotBlank(shopJson)) { //3.存在直接返回 return JSONUtil.toBean(shopJson, type);//R的类型是type所以反序列化这边放的是type } //判断命中的是否是空值 if(shopJson !null){ //返回一个错误信息 return null; } //4.不存在根据id查询数据库 R r dbFallback.apply(id);//因为范型这边的查数据库语句不好写不像idname这种数据库都有的字段所以要定义一个函数从外面传 //5.不存在返回错误 if (rnull) { //将空值写入redis stringRedisTemplate.opsForValue().set(key,,CACHE_NULL_TTL,TimeUnit.MINUTES); //返回错误信息 return null; } //6.存在写入redis this.set(key,r, time, unit); //这个时间注意应该是传的时间而不是直接写死的 //因为用的是opsForValue所以是value是string类型的所以后面的shop还得转为string //7.返回 return r; }因为是封装的缓存工具所以不确定返回值类型是什么所以要用泛型用R来代表返回值 ClassR type这个是泛型的推荐方便将来告诉具体是什么类型R的类型就是type。id的类型不一定是long类型的不能写死所以id的类型也不确定所以也要用泛型。 R r dbFallback.apply(id);因为范型这边的查数据库语句不好写不像idname这种数据库都有的字段所以要定义一个函数从外面传所以这里的代码是一个数据库查询的逻辑。因为是个有参有返回的函数所以用的是FunctiondbFallback是数据库的后备逻辑在这段代码里面的意思是先查redisredis查失败了才走它所以是后备逻辑。Shop shop cacheClient.queryWithPassThrough (CACHE_SHOP_KEY,id,Shop.class, this::getById,CACHE_SHOP_TTL,TimeUnit.MINUTES);1.4利用逻辑过期时间解决缓存击穿private static final ExecutorService CACHE_REBUILD_EXECUTOR Executors.newFixedThreadPool(10); //创建一个线程池 public R,ID R queryWithLogicalExpire( String keyPrefix, ID id, ClassR type , FunctionID ,R dbFallback,Long time, TimeUnit unit){ String key keyPrefix id;//把这个转为字符串方便使用前面标明cache shop 方便区分id //1.从redis查缓存 String json stringRedisTemplate.opsForValue().get(key);//以店铺id做为key,这样就得到店铺的json字符串 //2.判断是否存在 if (StrUtil.isBlank(json)) { //3.存在直接返回 return null; } //4.命中需要先把json反序列化为对象 RedisData redisData JSONUtil.toBean(json, RedisData.class); R r JSONUtil.toBean((JSONObject) redisData.getData(), type); LocalDateTime expireTime redisData.getExpireTime(); //5.判断是否过期 if (expireTime.isAfter(LocalDateTime.now())){ //5.1.未过期直接返回店铺信息 return r; } //5.2.已过期需要缓存重建 //6.缓存重建 //6.1获取互斥锁 String lockKey LOCK_SHOP_KEY id; boolean isLock tryLock(lockKey); //6.2判断是否获取锁成功 if (isLock){ //TODO 6.3成功开启独立线程实现缓存重建 //注意获取锁成功应该再次检测redis缓存是否过期做DoubleCheck。如果存在则无需重建缓存 CACHE_REBUILD_EXECUTOR.submit(() -{ try { //重建缓存 //查询数据库 R r1 dbFallback.apply(id); //写入Redis this.setWithLogicalExpire(key,r1,time,unit); } catch (Exception e) { throw new RuntimeException(e); }finally { //释放锁 unLock(lockKey); } }); } //6.4.失败返回过期商铺信息 return r; }Shop shop cacheClient.queryWithLogicalExpire (CACHE_SHOP_KEY, id,Shop.class,this::getById,20L,TimeUnit.SECONDS);

相关新闻

TVA具身智能架构:TVA-World系统相容性新范式

TVA具身智能架构:TVA-World系统相容性新范式

2026/9/2 6:15:28

前沿技术探索:TVA智能体(简称TVA) TVA智能体(亦称“AI智能体视觉”或“TVA视觉智能体”)是依托Transformer架构与“因式智能体”理论构建的通用视觉技术体系。它有机融合深度强化学习(DRL)、卷…

Polaris复现笔记(从准备到成功进入页面登陆)

Polaris复现笔记(从准备到成功进入页面登陆)

2026/9/2 6:15:28

我的电脑已经有VMware Workstation Pro,直接在VMware里面装Ubuntu系统。 一、 下载Ubuntu镜像 从官网https://link.wtturl.cn/?targethttps%3A%2F%2Freleases.ubuntu.com%2F24.04%2F&sceneim&aid497858&langzh 下载ubuntu-24.04.3-live-server-amd64.i…

AI卫星系统如何让地球保持宜居?工程视角下的技术拆解与落地路径

AI卫星系统如何让地球保持宜居?工程视角下的技术拆解与落地路径

2026/9/2 6:15:28

马斯克提出用 AI 卫星系统让地球在约 10 亿年内保持宜居,听起来像是把科幻设定直接端到了工程桌上。但这个设想最值得关注的地方不在于“10 亿年”这个时间数字,而在于它同时挑战了两件事:卫星系统能不能从“观测工具”变成“调控基础设施”&…

CPU实时多人姿态估计:33+FPS优化方案与工程实践

CPU实时多人姿态估计:33+FPS优化方案与工程实践

2026/9/2 7:25:31

简介:这是一份面向计算机视觉初学者与实战开发者的轻量级多人姿态估计开源实现,聚焦CPU端实时推理(FPS≥33),适用于无GPU环境下的快速验证与教学演示。资源包含21个文件,涵盖7个OpenVINO格式模型XML描述文件…

英伟达财报不只是科技股考试:AI狂欢正在接受全球资本市场的第二次验证

英伟达财报不只是科技股考试:AI狂欢正在接受全球资本市场的第二次验证

2026/9/2 7:25:31

如果把2026年的全球资本市场浓缩成一个关键词,那么“AI”依然占据最重要的位置。但与两三年前不同的是,市场如今已经不满足于听AI故事。投资者开始提出更加现实的问题:AI到底能带来多少收入?巨额数据中心投资什么时候能够回本&…

三菱Q系列PLC填表式通信实现Modbus RTU数据采集与设备控制

三菱Q系列PLC填表式通信实现Modbus RTU数据采集与设备控制

2026/9/2 7:25:31

在实际工业自动化项目中,PLC与第三方设备(如仪表、变频器、传感器)的通信是核心需求。三菱Q系列PLC功能强大,但其原生通信指令(如RS指令)在应对Modbus RTU这类标准协议时,往往需要开发者编写大量…

MFD、MFC与MATLAB工具箱:从硬件逻辑到软件界面的高效开发实践

MFD、MFC与MATLAB工具箱:从硬件逻辑到软件界面的高效开发实践

2026/9/2 7:25:31

简介:本资源是面向控制工程领域研究人员与高年级本科生的MATLAB多变量频域设计工具箱(MFD),聚焦MIMO系统控制器设计、频域分析与实验验证等核心问题,特别适用于化工、航空、电力等强耦合多变量过程控制系统建模与优化场…

小白程序员轻松掌握大模型技能,提升工作效率

小白程序员轻松掌握大模型技能,提升工作效率

2026/9/2 7:25:31

本文介绍了大模型技能的概念、使用方法和优势,帮助读者了解如何通过技能来封装和复用工作流程,提高工作效率。文章详细讲解了技能的组成、触发机制、与命令和MCP的分工,以及如何编写带脚本的强力技能等内容,适合想要学习大模型技能…

Focas1/2+协议深度解析:C/C++直连Fanuc数控系统实战指南

Focas1/2+协议深度解析:C/C++直连Fanuc数控系统实战指南

2026/9/2 7:15:31

简介:本资源是面向工业自动化开发工程师、数控系统集成人员及C/C嵌入式开发者的技术资料包,聚焦FANUC数控系统FOCAS 1/2通信接口的工程化应用,解决设备数据采集、远程监控与参数动态配置等核心问题。压缩包共105个文件,涵盖17个DL…

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

2026/9/1 1:53:39

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

2026/9/1 9:55:14

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

2026/9/1 23:49:08

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

2026/9/2 0:04:59

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

2026/9/2 0:04:59

这次我们来看一个很实用的 DeepSeek 落地场景:用 DeepSeek 把英文视频字幕自动翻译成中文。具体案例是《恶魔君》1989 年第 28 集的英转中字幕任务,标题写得很直白,但背后其实是一整套可以复用的技术流程:字幕解析、模型调用、批量…

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

2026/9/2 0:04:59

当你家里摆着一台天猫精灵,却总希望语音助手偶尔“不正经”一点,不用官方腔回答问题,而是张口就接几句搞笑段子,会是什么体验?我最近动手验证了一下这个想法——没有去改装任何市面上现有的智能音箱,而是直…

远程协作的工作台整理

远程协作的工作台整理

2026/9/2 6:21:32

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/2 6:21:32

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/2 2:45:06

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…