Redis专题-实战篇二-商户查询缓存

本文涉及的产品
多模态交互后付费免费试用,全链路、全Agent
简介: 本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。

一、什么是缓存

  1. 缓存:是数据存的缓冲区,是存储数据的地方,一般读写性能较好
  2. 以WEB访问,缓存存在的各个地方
  1. 浏览器缓存:静态的CSS、JS脚本或图片
  2. Tomcat缓存:使用Redis对于

  1. 缓存的优缺点

二、查询商户的业务流程

三、具体业务代码实现

  1. 具体代码实现
package com.hmdp.service.impl;
import cn.hutool.Hutool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONNull;
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 io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import static com.hmdp.utils.RedisConstants.CACHE_SHOP_KEY;
/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author
 * @since 2021-12-22
 */
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 通过ID查询商铺的详细信息
     * @param id
     * @return
     */
    @Override
    public Result querById(Long id) {
        String redisId = CACHE_SHOP_KEY +id;
        // 1 先通过redis查询
        String s = stringRedisTemplate.opsForValue().get(redisId);
        if (StrUtil.isNotBlank(s)) {
            Shop shop = JSONUtil.toBean(s, Shop.class);
            return Result.ok(shop);
        }
        // 返回空,查询数据库
        Shop shop = getById(id);
        // 数据库返回空,返回错误信息
        if (shop==null) {
            return Result.fail("商户不存在");
        }
        // 不为空返回数据并将数据存储在redis中
        stringRedisTemplate.opsForValue().set(redisId,JSONUtil.toJsonStr(shop));
        return Result.ok(shop);
    }
}
  1. 效果对比
  1. 查询数据库

  1. 查询redis

四、练习题:商铺分类列表redis缓存改造

  1. 实现方法和上章节类似,但是采用的存储方法为Zset
  2. 实现代码
package com.hmdp.service.impl;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.ShopType;
import com.hmdp.mapper.ShopTypeMapper;
import com.hmdp.service.IShopTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.xml.internal.bind.v2.runtime.reflect.Lister;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;
/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Slf4j
@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryTypeList() {
        String key = "catch:shopType";
        Set<String> range = stringRedisTemplate.opsForZSet().range(key, 0, 10);
      List<ShopType> list= new ArrayList<>();
        if (range.size()!=0) {
            range.stream().forEach(item ->{
                ShopType bean = JSONUtil.toBean(item, ShopType.class);
                list.add(bean);
            });
            log.debug("redis get catch:shopType");
        return Result.ok(list);
        }
        List<ShopType> sort = query().orderByAsc("sort").list();
        if (sort.size()==0) {
            return  Result.fail("系统错误");
        }
        HashSet<ShopType> shopTypes = new HashSet<>();
        shopTypes.stream().forEach(item->{
            stringRedisTemplate.opsForZSet().add(key,JSONUtil.toJsonStr(item),item.getSort());
        });
        log.debug("Mysql get shopTypeList");
        return Result.ok(sort);
    }
}

五、缓存更新策略

1. 三种策略模式

2. 策略选择分析

  • 低一致性需求:使用内存淘汰机制。例如店铺类型的查询缓存
  • 高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存

3. 主动更新策略的三种实现业务方式

  1. 在实际开发中常使用的为方法付01

  1. 使用方法需要注意的三点问题:
  1. 点三建议使用,先操作数据库,在删除缓存

  1. 点三先删除缓存,在操作操作数据存在的线程不一致问题
  1. 正常

  1. 异常

  1. 点三 先操作数据库,在删除缓存
  1. 正常

  1. 异常(条件:缓存已经失效的场景)
  1. 此异常发生需要的条件
  1. 两个线程并行执行
  2. 线程1查询时,恰巧缓存失效,并已经查询完了数据库,准备写缓存了
  3. 在写缓存的的同时,恰巧出现了一个线程开始更新数据库

4. 总结

六 、 练习题:给查询商铺的缓存添加超时剔除和主动更新的策略

七、缓存穿透

  1. 缓存穿透:是指客户端请求的数据在缓存和数据库中都不存在。
  1. 这样缓存就不会生效,这些请求都会打到数据库中。
  1. 现象:
  1. 当用户使用多个根本不存在的ID查询数据时,因为不存在所以最后都会去查询数据库。从而导致数据库被进行大量的空访问。

1. 解决方法一:缓存空对象

  1. 特点:

  1. 流程:

2. 解决方法二:布隆过滤器

  1. 在过滤器中保证,没有的不存在的id拦截,存在的id可能到最后也是不存在
  1. 会小概率的出现缓存穿透。
  1. 特点:

  1. 流程:

3. 缓存空对象的方法实践

  1. 流程:

  1. 需要修改的地方:
  1. 如果不存在就将在redis中存储一个空对象
  2. 在判断通过key查询redis中的数据时,多加一个判断,判断查询到的数据是否为null,为null,直接结束,返回警告信息。
@Override
    public Result querById(Long id) {
        String redisId = CACHE_SHOP_KEY +id;
        // 1 先通过redis查询
        String s = stringRedisTemplate.opsForValue().get(redisId);
        if (StrUtil.isNotBlank(s)) {
            Shop shop = JSONUtil.toBean(s, Shop.class);
            return Result.ok(shop);
        }
        if (s==""){
            return Result.fail("商户不存在");
        }
        // 返回空,查询数据库
        Shop shop = getById(id);
        // 数据库返回空,返回错误信息
        if (shop==null) {
            //存储缓存空对象
            stringRedisTemplate.opsForValue().set(redisId,"",2L, TimeUnit.MINUTES); // 60分钟
            return Result.fail("商户不存在");
        }
        // 不为空返回数据并将数据存储在redis中
        stringRedisTemplate.opsForValue().set(redisId,JSONUtil.toJsonStr(shop),60L, TimeUnit.MINUTES); // 60分钟
        return Result.ok(shop);
    }

4. 总结

目录
相关文章
|
9天前
|
人工智能 运维 安全
|
7天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
B站开源IndexTTS2,用极致表现力颠覆听觉体验
在语音合成技术不断演进的背景下,早期版本的IndexTTS虽然在多场景应用中展现出良好的表现,但在情感表达的细腻度与时长控制的精准性方面仍存在提升空间。为了解决这些问题,并进一步推动零样本语音合成在实际场景中的落地能力,B站语音团队对模型架构与训练策略进行了深度优化,推出了全新一代语音合成模型——IndexTTS2 。
676 23
|
8天前
|
人工智能 测试技术 API
智能体(AI Agent)搭建全攻略:从概念到实践的终极指南
在人工智能浪潮中,智能体(AI Agent)正成为变革性技术。它们具备自主决策、环境感知、任务执行等能力,广泛应用于日常任务与商业流程。本文详解智能体概念、架构及七步搭建指南,助你打造专属智能体,迎接智能自动化新时代。
|
14天前
|
人工智能 JavaScript 测试技术
Qwen3-Coder入门教程|10分钟搞定安装配置
Qwen3-Coder 挑战赛简介:无论你是编程小白还是办公达人,都能通过本教程快速上手 Qwen-Code CLI,利用 AI 轻松实现代码编写、文档处理等任务。内容涵盖 API 配置、CLI 安装及多种实用案例,助你提升效率,体验智能编码的乐趣。
1113 110
|
人工智能 数据可视化 数据挖掘
Quick BI 体验&征文有奖!
瓴羊生态推出Quick BI 征文激励计划,鼓励用户分享数据分析实践经验与技术洞察,征集高质量原创文章。内容围绕AI功能体验与BI案例实践,设季奖、年奖及参与奖,优秀作者可获现金奖励、产品内测资格及官方认证形象。投稿截止至2026年3月31日。
Quick BI 体验&征文有奖!