当前位置: 首页 > 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.wxhsa.cn/company.asp?id=3632

相关文章:

  • 高阻态
  • 鸿蒙应用开发从入门到实战(四):ArkTS 语言概述
  • 命令模式的深度解析:从标准实现到TPL Dataflow高性能架构
  • JavaWeb
  • 读书笔记:为什么数据在磁盘上的存放顺序如此重要?
  • Rcc_APBPeriphClockCmd()
  • 故障处理:ORA-19809: limit exceeded for recovery files
  • ORA-01555系列:二、ORA-01555的场景分析与解决方案
  • PySimpleGUI常用控件
  • 25.09.14 与其感慨路难行,不如马上出发
  • GCC工具链应用学习笔记
  • 初始化 MCP 环境 创建 MCP Server (一)
  • 博客园格式设置
  • [总结/备赛]备战 CSP-S 2025 初赛总结
  • win11 系统如何进行硬盘分区?固态硬盘怎么分区?SSD 固态硬盘是分区好还是不分区好?
  • 逆序数及其应用
  • 豆豆守护如何下载?
  • Java运行时jar时终端输出的中文日志是乱码
  • ZK2真空发生器日常清理
  • Nacos服务注册与发现
  • 马的遍历
  • 20231310王宏邦《密码系统设计》第1周
  • 新学期第一次随笔:慢慢学,总会有进步
  • 详细介绍:【C语言】第四课 指针与内存管理
  • 知识点错题整理
  • 202311_陇剑杯预赛_tcpdump
  • Linux学习记录(六):添加/删除用户
  • python 链式调用 合并 __setattr__ __getattribute__ in nested object()
  • 分享一个稳定好用的免费云服务——阿贝云体验
  • 年化439%,回撤7%,卡玛比率62.5,附本地运行的完整策略python代码 - 详解