前言: 👏作者简介:我是笑霸final,一名热爱技术的在校学生。 📝个人主页:个人主页1 || 笑霸final的主页2 📕系列专栏:《项目专栏》 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

🐉商户查询缓存 介绍
上节回顾
仿黑马点评-redis整合【邮件登陆部分】点此查看
本节梳理
解决缓存穿透、缓存击穿的问题
🐉添加redis缓存
流程 
代码
@Override
public Result queryById(Long id) {
String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
if (StrUtil.isNotBlank(shopJson)) {
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
Shop shop = getById(id);
if (shop==null) return Result.fail("没有此店铺");
String toJsonStr = JSONUtil.toJsonStr(shop);
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,toJsonStr);
return Result.ok(shop);
}
🐉给店铺类型查询添加缓存(作业)
分析步骤我们还是可以拿上面的图  代码
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Result findList() {
String s = stringRedisTemplate.opsForValue().get("cache:list");
if (StrUtil.isNotBlank(s)) {
List<ShopType> dtoList=JSONUtil.toList(s,ShopType.class);
log.info("redis返回的数据");
return Result.ok(dtoList);
}
List<ShopType> typeList = this.query().orderByAsc("sort").list();
if (typeList.isEmpty()) {
return Result.fail("错误");
}
String s1 = JSONUtil.toJsonStr(typeList);
stringRedisTemplate.opsForValue().set("cache:list",s1);
return Result.ok(typeList);
}
效果
🐉缓存的更新策略
缓存的更新策略的方案 上面加入redis缓存我自己加了超时剔除
🐉缓存存在的问题
下面代码访问的路径 http://localhost:8081/shop/1
1.缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种:
- 缓存空对象
优点:实现简单,维护方便 缺点:额外的内存消耗,可能造成短期的不一致 适合命中不高,但可能被频繁更新的数据 - 布隆过滤
优点:内存占用较少,没有多余key 缺点:实现复杂,存在误判可能 适合命中不高,但是更新不频繁的数据 
@Override
public Result queryById(Long id) {
String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
if (StrUtil.isNotBlank(shopJson)) {
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
if(shopJson==""){
return Result.fail("不存在此店铺");
}
Shop shop = getById(id);
if(shop==null){
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,"",2, TimeUnit.MINUTES);
return Result.fail("不存在此店铺");
}
String toJsonStr = JSONUtil.toJsonStr(shop);
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,toJsonStr,2, TimeUnit.MINUTES);
return Result.ok(shop);
}
2.缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。 解决方案:
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
3.缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。 常见的解决方案有两种:
- 互斥锁
- 逻辑过期

 
互斥锁
互斥锁解决方法
最大的问题就是互相等待  相关方法 
public Result queryById(Long id) {
String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
if (StrUtil.isNotBlank(shopJson)) {
Shop shop = JSONUtil.toBean(shopJson, Shop.class);
return Result.ok(shop);
}
if(shopJson!=null){
return Result.fail("不存在此店铺");
}
String lockKey="Key:shop:"+id;
try {
boolean isLock = tryLock(lockKey);
if (!isLock){
Thread.sleep(50);
return queryById(id);
}
Shop shop = getById(id);
if(shop==null){
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,"",2, TimeUnit.MINUTES);
return Result.fail("不存在此店铺");
}
String toJsonStr = JSONUtil.toJsonStr(shop);
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id,toJsonStr,2, TimeUnit.MINUTES);
return Result.ok(shop);
}catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
unlock(lockKey);
}
}
逻辑过期
逻辑过期解决方法
 相关数据   线程池
String key = RedisConstants.CACHE_SHOP_KEY + id;
String json = stringRedisTemplate.opsForValue().get(key);
if (StrUtil.isBlank(json)) {
return null;
}
RedisData redisData = JSONUtil.toBean(json, RedisData.class);
JSONObject data = (JSONObject) redisData.getData();
Shop shop = JSONUtil.toBean(data,Shop.class);
LocalDateTime expireTime = redisData.getExpireTime();
if(expireTime.isAfter(LocalDateTime.now())){
return Result.ok(shop);
}
String lockkey = "lock:shop:" + id;
boolean lock = tryLock(lockkey);
if(lock){
ExcutorService_CACHE_RECUTOR.submit(()->{
try {
this.saveShopToRdis(id,30L);
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
unlock(lockkey);
}
});
}
return Result.ok(shop);
}
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏
|