封装Redis工具类(解决击穿,穿透)

基于StringRedisTemplate封装一个缓存工具类

Redis实战篇 | Kyle's Blog (cyborg2077.github.io)

目录

方法1:将任意Java对象序列化为JSON,并存储到String类型的Key中,并可以设置TTL过期时间

方法2:将任意Java对象序列化为JSON,并存储在String类型的Key中,并可以设置逻辑过期时间,用于处理缓存击穿问题

方法3:根据指定的Key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题

方法4:根据指定的Key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题

方法5:根据指定的Key查询缓存,并反序列化为指定类型,需要利用互斥锁解决缓存击穿问题 


方法1:将任意Java对象序列化为JSON,并存储到String类型的Key中,并可以设置TTL过期时间

    public void set(String key, Object value, Long time, TimeUnit timeUnit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, timeUnit);}

方法2:将任意Java对象序列化为JSON,并存储在String类型的Key中,并可以设置逻辑过期时间,用于处理缓存击穿问题

    public void setWithLogicExpire(String key, Object value, Long time, TimeUnit timeUnit) {//由于需要设置逻辑过期时间,所以我们需要用到RedisDataRedisData redisData = new RedisData();//redisData的data就是传进来的value对象redisData.setData(value);//逻辑过期时间就是当前时间加上传进来的参数时间,用TimeUnit可以将时间转为秒,随后与当前时间相加redisData.setExpireTime(LocalDateTime.now().plusSeconds(timeUnit.toSeconds(time)));//由于是逻辑过期,所以这里不需要设置过期时间,只存一下key和value就好了,同时注意value是ridisData类型stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}

@Data
public class RedisData<T> {private LocalDateTime expireTime;private T data;
}

方法3:根据指定的Key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题

  • 改为通用方法,那么返回值就需要进行修改,不能返回Shop了,那我们直接设置一个泛型,同时ID的类型,也不一定都是Long类型,所以我们也采用泛型。
  • Key的前缀也会随着业务需求的不同而修改,所以参数列表里还需要加入Key的前缀
  • 通过id去数据库查询的具体业务需求我们也不清楚,所以我们也要在参数列表中加入一个查询数据库逻辑的函数
  • 最后再加上设置TTL需要的两个参数
  • 那么综上所述,我们的参数列表需要
    1. key前缀
    2. id(类型泛型)
    3. 返回值类型(泛型)
    4. 查询的函数
    5. TTL需要的两个参数
public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit timeUnit) {//先从Redis中查,这里的常量值是固定的前缀 + 店铺idString key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);//如果不为空(查询到了),则转为R类型直接返回if (StrUtil.isNotBlank(json)) {return JSONUtil.toBean(json, type);}if (json != null) {return null;}//否则去数据库中查,查询逻辑用我们参数中注入的函数R r = dbFallback.apply(id);//查不到,则将空值写入Redisif (r == null) {stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//查到了则转为json字符串String jsonStr = JSONUtil.toJsonStr(r);//并存入redis,设置TTLthis.set(key, jsonStr, time, timeUnit);//最终把查询到的商户信息返回给前端return r;
}

public Result queryById(Long id) {Shop shop = cacheClient.queryWithPassThrough(CACHE_SHOP_KEY, id, Shop.class, this::getById, CACHE_SHOP_TTL, TimeUnit.MINUTES);if (shop == null) {return Result.fail("店铺不存在!!");}return Result.ok(shop);
}

方法4:根据指定的Key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题

public <R, ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit timeUnit) {//1. 从redis中查询商铺缓存String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);//2. 如果未命中,则返回空if (StrUtil.isBlank(json)) {return null;}//3. 命中,将json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);LocalDateTime expireTime = redisData.getExpireTime();//4. 判断是否过期if (expireTime.isAfter(LocalDateTime.now())) {//5. 未过期,直接返回商铺信息return r;}//6. 过期,尝试获取互斥锁String lockKey = LOCK_SHOP_KEY + id;boolean flag = tryLock(lockKey);//7. 获取到了锁if (flag) {//8. 开启独立线程CACHE_REBUILD_EXECUTOR.submit(() -> {try {R tmp = dbFallback.apply(id);this.setWithLogicExpire(key, tmp, time, timeUnit);} catch (Exception e) {throw new RuntimeException(e);} finally {unlock(lockKey);}});//9. 直接返回商铺信息return r;}//10. 未获取到锁,直接返回商铺信息return r;
}

方法5:根据指定的Key查询缓存,并反序列化为指定类型,需要利用互斥锁解决缓存击穿问题 

public <R, ID> R queryWithMutex(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit timeUnit) {//先从Redis中查,这里的常量值是固定的前缀 + 店铺idString key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);//如果不为空(查询到了),则转为Shop类型直接返回if (StrUtil.isNotBlank(json)) {return JSONUtil.toBean(json, type);}if (json != null) {return null;}R r = null;String lockKey = LOCK_SHOP_KEY + id;try {//否则去数据库中查boolean flag = tryLock(lockKey);if (!flag) {Thread.sleep(50);return queryWithMutex(keyPrefix, id, type, dbFallback, time, timeUnit);}r = dbFallback.apply(id);//查不到,则将空值写入Redisif (r == null) {stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//并存入redis,设置TTLthis.set(key, r, time, timeUnit);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {unlock(lockKey);}return r;
}

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

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

相关文章

NSSCTF-Web题目12

目录 [SWPUCTF 2021 新生赛]finalrce 1、题目 2、知识点 3、思路 [UUCTF 2022 新生赛]ez_rce 1、题目 2、知识点 3、思路 [羊城杯 2020]easycon 1、题目 2、知识点 3、思路 [SWPUCTF 2021 新生赛]finalrce 1、题目 2、知识点 命令执行&#xff0c;tee命令 3、思路…

深度学习算法informer(时序预测)(三)(Encoder)

一、EncoderLayer架构如图&#xff08;不改变输入形状&#xff09; 二、ConvLayer架构如图&#xff08;输入形状中特征维度减半&#xff09; 三、Encoder整体 包括三部分 1. 多层EncoderLayer 2. 多层ConvLayer 3. 层归一化 代码如下 class AttentionLayer(nn.Module):de…

学习Vue 3中的浅拷贝与数组操作

学习Vue 3中的浅拷贝与数组操作 一、前言1.什么是浅拷贝&#xff1f;2.为什么需要浅拷贝&#xff1f;3.在Vue 3中使用浅拷贝进行数组操作3.1使用展开运算符进行浅拷贝3.2使用push方法添加新内容 4.注意事项5.结语 一、前言 在Vue 3应用程序开发中&#xff0c;我们经常需要对数…

淘宝扭蛋机小程序:互联网时代下行业的发展动力

近几年&#xff0c;扭蛋机在潮玩市场风靡&#xff0c;与各类IP合作&#xff0c;推出各种新颖有趣的扭蛋商品&#xff0c;吸引了众多的IP粉丝&#xff0c;他们会通过扭蛋机进行抽奖&#xff0c;获得喜欢的商品。 目前&#xff0c;移动应用程序不断升级优化&#xff0c;“互联网…

idea中的git在clone文件提示 filename too long

一 解决版本 1.1 问题描述以及解决办法 当在Windows系统下使用Git时出现“filename too long”错误&#xff1a; git config --system core.longpaths true

思科ospf+rip重发布配置命令

——————————————————————————————————————————— 基础配置 R1 Router>en #进入配置模式 Router#conf #进入配置模式 Router(config)#h…

如何在 MySQL 中创建和使用事务?

目录 1. 环境准备 2. 创建事务 3. 事务执行 4. 事务撤消 5. 总结 事务是数据库区别于文件系统的重要特征之一&#xff0c;当我们有了事务就会让数据库始终保持一致&#xff0c;同时我们还能通过事务机制恢复到某个时间点&#xff0c;这样可以保证已提交到数据库的修改不会…

人工智能在肿瘤检测以及癌症早筛中的最新研究|顶刊速递·24-06-21

小罗碎碎念 推文主题&#xff1a;人工智能在癌症检测以及早筛中的最新研究进展 之前有一篇推文介绍了哈佛发表的3D病理&#xff0c;当时应该有不少老师/同学对于数据的获取是有些懵的&#xff0c;那么今天你在第一篇文章中或许能找到答案。 一直看我推送的&#xff0c;并且不跳…

骁龙相机启动流程分析

一、骁龙相机启动流程分析 1. 相机启动阶段关键TAG 关键字解释deliverInputEvent点击事件bindApplicationApp 冷启动 创建applicationactivityStart创建camera activityactivityResumecamera UI界面开始显示connectDevicecameraFWK 开始链接并open sensorCameraHal::openSessio…

发那科 偏移实现三维码垛

1: OVERRIDE5% ;2: UFRAME_NUM0 ;3: UTOOL_NUM2 ;4: CALL TOOL_OFF ;5:J P[1:home] 30% FINE ;6: FOR R[3]0 TO 2 ;7: FOR R[1]0 TO 1 ;8: FOR R[2]0 TO 3 ;9: PR[5:偏移]LPOS-LPOS ;10: PR[5,3:偏移](PR[5,3:偏移]-5*(R[1]*4R[2]R[3]*8)) ;11: OFFSET COND…

MySQL系列-安装配置使用说明(MAC版本)

1、前言 本文将介绍MySQL的安装配置以及基本语法操作说明 环境&#xff1a;mac 版本&#xff1a;MySQL 8.0.28 之前电脑安装卸载过&#xff0c;后面在装的时候遇到一些问题&#xff0c;用了四五天才解决&#xff0c;主要是参考 https://blog.csdn.net/zz00008888/article/deta…

大厂晋升学习方法一:海绵学习法

早晨 30 分钟 首先&#xff0c;我们可以把起床的闹钟提前 30 分钟&#xff0c;比如原来 07:30 的闹钟可以改为 07:00。不用担心提前 30 分钟起床会影响休息质量&#xff0c;习惯以后&#xff0c;早起 30 分钟不但不会影响一天的精力&#xff0c;甚至可能反而让人更有精神。早起…

BUG:AttributeError: module ‘numpy‘ has no attribute ‘bool‘.

BUG:AttributeError: module ‘numpy’ has no attribute ‘bool’. 环境 Linux numpy 1.26.3详情 使用NumPy库时遇到&#xff1a;AttributeError: module numpy has no attribute bool报错。 错误原因 目前最新的的NumPy版本&#xff08;如1.26版本&#xff09;中布尔类型…

SAP ScreenPersonas

https://developers.sap.com/mission.screen-personas.html 跟着这个练习做一遍就了解了Personas 访问SAP提供的Personas练习系统 申请用户 登录练习系统 随便找一个可以支持Personas的程序搞起来&#xff0c;比如IW51 执行后等它出现这个图标就可以开始了.

js中的window和Window

示例&#xff1a; window.name name; console.log(window.name) // name console.log(Window.name) // Window由此可见Window和window是有区别的。 console.log(Object.prototype.toString.call(Window)); // [object Function] console.log(Object.prototype.toString.c…

服务器雪崩的应对策略之----超时设置

在服务器编程中&#xff0c;超时设置&#xff08;Timeout Configuration&#xff09;是确保系统稳定性和提高性能的重要手段。合理的超时设置可以防止长时间等待导致的资源浪费&#xff0c;并在依赖服务不可用时快速响应&#xff0c;从而避免系统陷入僵局。下面介绍几种常见的超…

中服云产品远程运维系统

中服云产品远程运维系统主要针对设备售后市场服务的管理&#xff0c;利用工业物联网技术&#xff0c;一方面面向设备生产厂商&#xff0c;将分散的经销商、客户、销售出去的设备统一管理&#xff1b;另一方面面向设备使用厂家&#xff0c;实现设备实时运行监控&#xff1b;系统…

融资融券有哪些优势和风险,融资融券利息怎么算,利率最低是?4.0

融资融券的优势 1. 提高资金利用率&#xff1a;获得额外的资金或股票交易&#xff0c;提高资金利用率&#xff0c;扩大投资规模。 2. 降低投资风险&#xff1a;通过融资融券买入多只股票分散风险&#xff0c;降低单一股票持仓风险。 3. 增加投资收益&#xff1a;提供更多的交…

视创云展为企业虚拟展厅搭建,提供哪些功能?

在当下数字化浪潮中&#xff0c;如何为用户创造更富生动性和真实感的展示体验&#xff0c;已成为企业营销策略的核心。借助视创云展的线上虚拟3D企业展厅搭建服务&#xff0c;利用3D空间漫游和VR技术的融合&#xff0c;可以为用户呈现出一个既真实又充满想象力的全景图或三维模…

Redis-数据类型-String

文章目录 1、通过客户端连接redis2、查看当前数据库的key的数量3、切换数据库3.1、切换到1数据库3.2、切换到2数据库3.3、切换到默认的数据库&#xff0c;0数据库 4、当前数据库没有数据5、添加键值对6、查看当前库所有key7、清空当前库8、设置存活的秒数&#xff08;例如验证码…