尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

redis实现缓存2-解决缓存穿透,缓存击穿

redis实现缓存2-解决缓存穿透,缓存击穿
📅 发布时间:2026/6/19 1:07:11

image

image

image

image

具体实现:
ShopServiceImpl

package com.hmdp.service.impl;import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisData;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;import static com.hmdp.utils.RedisConstants.*;/*** <p>*  服务实现类* </p>** @author ztn* @since 2025-9-12*/
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@ResourceStringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {// 缓存穿透// Shop shop = queryWithPassThrough(id);// 互斥锁解决缓存击穿// Shop shop = queryWithMutex(id);// 逻辑过期解决缓存击穿Shop shop = queryWithLogicalExpire(id);if (shop == null) {return Result.fail("店铺不存在!");}// 7.返回return Result.ok(shop);}private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);public Shop queryWithLogicalExpire(Long id){// 1.从redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 2.判断是否存在if(StrUtil.isBlank(shopJson)){// 3.存在,直接返回return null;}// 4.命中,把json反序列化为对象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);LocalDateTime expireTime = redisData.getExpireTime();// 5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())){// 5.1未过期,直接返回店铺信息return shop;}// 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 {this.saveShop2Redis(id,20L);} catch (Exception e) {throw new RuntimeException(e);} finally {//释放锁unlock(lockKey);}});}// 6.4 返回过期的店铺信息return shop;}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);}public Shop queryWithMutex(Long id){// 1.从redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 2.判断是否存在if(StrUtil.isNotBlank(shopJson)){// 3.存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}// 判断命中的是否是空值if(shopJson != null){return null;}// 4.实现缓存重建// 4.1获取互斥锁String lockKey = LOCK_SHOP_KEY +id;Shop shop = null;try {boolean isLock = tryLock(lockKey);// 4.2判断是否获取成功if(!isLock){// 4.3失败,则休眠并重试Thread.sleep(50);return queryWithMutex(id);}// 4.4成功,根据id查询数据库shop = getById(id);//模拟重建的延时Thread.sleep(200);// 5.不存在,返回错误if(shop == null){//将空值写入reidsstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "",CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}// 6.存在,写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {// 7.返回unlock(lockKey);}// 8.返回return shop;}public Shop queryWithPassThrough(Long id){// 1.从redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 2.判断是否存在if(StrUtil.isNotBlank(shopJson)){// 3.存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}// 判断命中的是否是空值if(shopJson != null){return null;}// 4.不存在,根据id查询数据库Shop shop = getById(id);// 5.不存在,返回错误if(shop == null){//将空值写入reidsstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, "",CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}// 6.存在,写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);// 7.返回return shop;}public void saveShop2Redis(Long id, Long expireSeconds) throws InterruptedException {// 1.查询店铺数据Shop shop = getById(id);Thread.sleep(200);// 2.封装逻辑过期时间RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));// 3.写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));}@Override@Transactionalpublic Result update(Shop shop) {Long id = shop.getId();if (id == null) {return Result.fail("店铺id不能为空");}// 1.更新数据库updateById(shop);// 2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY + id);return Result.ok();}
}

相关新闻

  • 单克隆抗体人源化:从鼠源缺陷到全人源突破,3 大阶段破解临床应用难题
  • C 语言实现动态数组、链表、栈与队列
  • git reset

最新新闻

  • 医疗AI落地两大硬坎:临床信任断裂与数据合规失焦
  • Adaboost原理深度解析:理解梯度提升家族的基石
  • 股市语言密码:看懂全球资本流动的翻译之道
  • 终极指南:如何为300+车型部署开源驾驶辅助系统openpilot
  • 2026年文旅行业GEO优化公司“全意图”价值评估指南与选型避坑 - GEO优化
  • MPC857T外部总线接口:对齐、仲裁与原子操作实战解析

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号