当前位置: 首页 > news >正文

redis实现缓存3-封装redis工具类

image

具体实现:

CacheClient

package com.hmdp.utils;import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;import static com.hmdp.utils.RedisConstants.*;@Slf4j
@Component
public class CacheClient {private final 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) {// 设置逻辑过期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));// 写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}public <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time, TimeUnit unit){// 1.从redis中查询商铺缓存String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);// 2.判断是否存在if(StrUtil.isNotBlank(json)){// 3.存在,直接返回return JSONUtil.toBean(json, type);}// 判断命中的是否是空值if(json != null){return null;}// 4.不存在,根据id查询数据库R r = dbFallback.apply(id);// 5.不存在,返回错误if(r == null){//将空值写入reidsstringRedisTemplate.opsForValue().set(key, "",CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}// 6.存在,写入redisthis.set(key, r, time, unit);// 7.返回return r;}private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);public <R,ID> R queryWithLogicalExpire(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time, TimeUnit unit){// 1.从redis中查询商铺缓存String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);// 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){// 6.3 成功,开启独立线程CACHE_REBUILD_EXECUTOR.submit(()->{try {// 查询数据库R r1 = dbFallback.apply(id);// 写入redisthis.setWithLogicalExpire(key, r1, time, unit);} catch (Exception e) {throw new RuntimeException(e);} finally {//释放锁unlock(lockKey);}});}// 6.4 返回过期的店铺信息return r;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}private void unlock(String key){stringRedisTemplate.delete(key);}
}

调用工具类:

    @Overridepublic Result queryById(Long id) {// 逻辑过期解决缓存击穿Shop shop = cacheClient.queryWithLogicalExpire(CACHE_SHOP_KEY,id,Shop.class,this::getById,20L,TimeUnit.SECONDS);// 缓存穿透// Shop shop = cacheClient.queryWithPassThrough(CACHE_SHOP_KEY,id,Shop.class,this::getById,CACHE_SHOP_TTL,TimeUnit.MINUTES);// 互斥锁解决缓存击穿// Shop shop = queryWithMutex(id);if (shop == null) {return Result.fail("店铺不存在!");}// 7.返回return Result.ok(shop);}
http://www.rkmt.cn/news/4458.html

相关文章:

  • 高阻态
  • ORA-01555系列:二、ORA-01555的场景分析与解决方案
  • Rcc_APBPeriphClockCmd()
  • 故障处理:ORA-19809: limit exceeded for recovery files
  • [总结/备赛]备战 CSP-S 2025 初赛总结
  • Java运行时jar时终端输出的中文日志是乱码
  • 20231310王宏邦《密码系统设计》第1周
  • 知识点错题整理
  • Linux学习记录(六):添加/删除用户
  • 接口测试---PyMysql
  • linux c应用性能与内存泄露问题排查工具
  • 去去就来
  • 高三试卷
  • 使用 CUDA 12.9 编译 PyTorch 2.4.0
  • 豆包生成C#即梦API HTTP调用实例代码
  • 复制一个数组的方法
  • 选择排序方法
  • ArcGIS Pro 遇到严重的应用程序错误而无法启动 - 教程
  • markdown文件上传到博客园教程
  • ffplay音频重采样 - 教程
  • 深入解析:Qt串口通信学习
  • 题解:P12546 [UOI 2025] Convex Array
  • 玩转 hostnamectl set-hostname:Linux 主机名管理的优雅方式 - 实践
  • Spring八股文 - 实践
  • Clion 基础设置
  • P3957 [NOIP 2017 普及组] 跳房子
  • JavaScript Array 对象
  • WebStorm代码一键美化
  • Golang中设置HTTP请求代理的策略
  • [开源免费] iGTTS(Gemini TTS) 文本转语音(TTS)的命令行工具。