redis工具类封装

1|0封装Redis工具类

  • 方法1:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间

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

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

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

    @Component @Slf4j public class CacheClient { private StringRedisTemplate stringRedisTemplate; private static final ExecutorService CACHE_REBUILD_EXECUTOR= Executors.newFixedThreadPool(10); public CacheClient(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate; } //方法1:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间 public void set(String key, Object value,Long time, TimeUnit unit){ String jsonStr = JSONUtil.toJsonStr(value); stringRedisTemplate.opsForValue().set(key,jsonStr,time,unit); } //方法2:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置逻辑过期时间, 用于处理缓存击穿问题 public void setWithLogicExpire(String key,Object value,Long time,TimeUnit unit){ //设置逻辑过期 RedisData redisData = new RedisData(); redisData.setData(value); redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); //写入Redis stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(redisData)); } //方法3:根据指定的key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题 public <R,ID> R queryWithPassThrought(String keyPrefix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time,TimeUnit timeUnit) { String key= keyPrefix +id; //1.从redis查询缓存数据 String json = stringRedisTemplate.opsForValue().get(key); //2.判断缓存数据是否存在 if (StringUtils.isNotBlank(json)){ //3.存在,直接返回 return JSONUtil.toBean(json, type); } //判断命中的是否为空值 if (json!=null){ //返回一个错误信息 return null; } //4.不存在,根据id查询 R r = dbFallback.apply(id); //5.不存在,返回错误 if (r==null){ //将空值写入Redis stringRedisTemplate.opsForValue().set(key,"",RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES); //返回错误信息 return null; } //6.写入redis set(key,r,time,timeUnit); return r; } //方法4:根据指定的key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题 public <R,ID> R queryWithLogicExpire(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit timeUnit){ String key= keyPrefix +id; //1.从redis查 String json = stringRedisTemplate.opsForValue().get(key); //2.判断是否存在 if (StringUtils.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())){ //未过期,直接返回 return r; } //5.已过期,缓存重建 //6.获取互斥锁 String lockKey=RedisConstants.LOCK_SHOP_KEY+id; boolean isLock = tryLock(lockKey); //判断是否获取锁成功 if (isLock){ CACHE_REBUILD_EXECUTOR.submit(()->{ try { //6.1查询数据库 R newR = dbFallback.apply(id); //6.2重建缓存 setWithLogicExpire(key,newR,time,timeUnit); } catch (Exception e) { throw new RuntimeException(e); } finally { //6.3释放锁 unlock(key); } }); } //7.获取锁失败,返回过期的信息 return r; } //方法4:根据指定的key查询缓存,并反序列化为指定类型,需要利用互斥锁解决缓存击穿问题 public <R, ID> R queryWithMutex(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit timeUnit){ String key=keyPrefix+id; //1.从redis查询 String json = stringRedisTemplate.opsForValue().get(key); //2.判断是否存在 if (StringUtils.isNotBlank(json)){ //存在直接返回 return JSONUtil.toBean(json,type); } //3.判断命中的是否为空值 if (json!=null){ //返回一个错误信息 return null; } //4.未命中,尝试获取互斥锁 String lockKey=RedisConstants.LOCK_SHOP_KEY+id; R r = null; try { boolean isLock = tryLock(lockKey); // 4.1获取失败,休眠后继续获取 if (!isLock){ Thread.sleep(50); //递归查询 return queryWithMutex(keyPrefix, id, type,dbFallback, time, timeUnit); } //4.2获取成功,查询数据库 r = dbFallback.apply(id); //4.3不存在,返回错误 if (r==null){ //将空值写入redis stringRedisTemplate.opsForValue().set(key,"",time,timeUnit); //返回错误信息 return null; } //4.4存在,写回Redis set(key,JSONUtil.toJsonStr(r),time,timeUnit); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { unlock(lockKey); } //5.返回数据 return r; } private boolean tryLock(String lockKey) { Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", RedisConstants.LOCK_SHOP_TTL, TimeUnit.SECONDS); return BooleanUtil.isTrue(flag); } private void unlock(String lockKey){ stringRedisTemplate.delete(lockKey); } }

__EOF__

本文作者userName
本文链接https://www.cnblogs.com/pdxpdx/p/17963669.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   天菜星  阅读(99)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示