点评项目——商户查询缓存

news2024/11/26 11:50:27

2023.12.7

redis实现商户查询缓存

        在企业开发中,用户的访问量动辄成百上千万,如果没有缓存机制,数据库将承受很大的压力。本章我们使用redis来实现商户查询缓存。

        原来的操作是根据商铺id直接从数据库查询商铺信息,为了防止频繁地对数据库访问,我们使用redis进行缓存,大致流程图如下:

         需要改变的地方就两个:①之前是直接从数据库中查,现在是先尝试从redis中查,没查到再去查数据库。②如果查数据库查到了的话,需要将查到的商铺数据先存到redis中,再将数据返回。       代码如下:

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result queryById(Long id) {
        String key = CACHE_SHOP_KEY + id;
        //1、从redis查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        //2、判断是否存在
        if(StrUtil.isNotBlank(shopJson)){
            //3、存在,直接返回
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        //4、不存在,根据id查询数据库
        Shop shop = getById(id);
        //5、数据库没查到数据,返回错误信息
        if (shop == null){
            return Result.fail("商铺不存在!");
        }
        //6、数据库查到信息了,写入redis并返回商铺信息
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop));

        return Result.ok(shop);

    }
}

redis实现商户类型数据缓存

        解决商户数据缓存之后,我们趁热打铁也完成一下商户类型数据缓存,即下面这张图中数据的缓存:

        而且这个页面数据也不会经常变动,很适合做缓存,需要变更的代码如下:

        首先修改 ShopTypeController.java文件,原来是直接从数据库中查数据,这里我们在Controller中自定义一个方法,在service实现类中去编写具体业务代码:

@RestController
@RequestMapping("/shop-type")
public class ShopTypeController {
    @Resource
    private IShopTypeService typeService;

    @GetMapping("list")
    public Result queryTypeList() {
//        List<ShopType> typeList = typeService
//                .query().orderByAsc("sort").list();
//        return Result.ok(typeList);
        return typeService.queryList();
    }
}

        对应的接口需要增加该方法:

public interface IShopTypeService extends IService<ShopType> {

    Result queryList();
}

        在对应的实现类ShopTypeServiceImpl.java中编写具体业务代码:

@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryList() {
        //1.尝试从redis中查询商户类型数据
        List<String> shopTypes = stringRedisTemplate.opsForList().range(CACHE_SHOP_TYPE_KEY, 0, -1);
        //2.在redis中查到数据了,返回ShopType类型数据
        if(!shopTypes.isEmpty()){
            List<ShopType> list = new ArrayList<>();
            for(String shopType : shopTypes){
                ShopType bean = JSONUtil.toBean(shopType, ShopType.class);
                list.add(bean);
            }
            return Result.ok(list);
        }
        //3.在redis中没查到数据,那就去数据库查
        List<ShopType> list = query().orderByAsc("sort").list(); //从数据库中按照sort字段升序查询
        //3.1 数据库也没查到,返回错误信息
        if(list == null){
            return Result.fail("店铺类型不存在!");
        }
        //3.2 数据库查到数据了,存入redis中并返回给用户
        for (ShopType shopType : list){
            String jsonStr = JSONUtil.toJsonStr(shopType);
            shopTypes.add(jsonStr);
        }
        stringRedisTemplate.opsForList().leftPushAll(CACHE_SHOP_TYPE_KEY,shopTypes);

        return Result.ok(list);
    }
}

       本人新手用的笨方法for-each循环逐个转换,高手可以用stream流来简化代码。

缓存更新策略

        由于内存资源比较宝贵,向其插入过多数据的话可能导致内存空间爆满,所以需要某种机制对内存的部分数据进行更新或者移除。下面介绍三种缓存更新数据:

  • 内存淘汰Redis自动进行,当Redis内存大到某个阈值时,会自动触发淘汰机制,淘汰掉一些不重要的数据(这个机制可以自定义)
  • 超时剔除当我们给Redis设置了过期时间TTL之后,Redis会将超时的数据进行删除。
  • 主动更新我们可以手动调用方法把缓存删除掉,通常用于解决缓存和数据库不一致问题,该方法一致性较好,但是维护成本高。

业务场景:

  • 在低一致性场景下:使用内存淘汰机制,因为该场景下的数据很长一段时间都不需要更新。
  • 在高一致性场景下:使用主动更新策略,即自己编写代码实现高一致性,但也不能100%的保证一致性,所以还需要使用超时剔除策略兜底。

数据库与缓存不一致的解决方案

        由于我们的缓存数据来自数据库,而数据库的数据是会发生变化的,因此,如果当数据库中数据发生变化,而缓存却没有同步更新,此时存在数据的一致性问题。

有三种解决方案:

  1. Cache Aside Pattern 人工编码方式:缓存调用者在更新完数据库之后再去更新缓存,也称之为双写方案
  2. Read/Write Through Pattern:缓存与数据库整合为一个服务,由服务来维护一致性。调用者调用该服务,无需关心缓存一致性问题。但是维护这样一个服务很复杂,市面上也不容易找到这样的一个现成的服务,开发成本高
  3. Write Behind Caching Pattern:调用者只操作缓存,其他线程去异步处理数据库,最终实现一致性。但是维护这样的一个异步的任务很复杂,需要实时监控缓存中的数据更新,其他线程去异步更新数据库也可能不太及时,而且缓存服务器如果宕机,那么缓存的数据也就丢失了

        实际开发中,一般还是使用方案一,但是如果我们每次操作完数据库之后,都去更新一下缓存,而此期间并没有人查询数据,那么这个更新动作意义就不大了,所以我们可以把缓存直接删除,等到有人再次查询时,再更新缓存

        还有个问题,我们应该先删缓存还是先更新数据库呢?理论上是都可以,如果先删缓存再更新数据库的话,由于删缓存的速度比更新数据库的速度快很多,所以两个操作之间有一段较长的空档期,此期间如果有其他线程进来查询数据库的话查的就是脏数据了。先更新数据库再删缓存当然也存在安全问题,但是几率会比上述小很多,这里不再细说,结论就是采用先更新数据库再删缓存的策略。

实现商铺缓存与数据库的双写一致

        主要需要修改两处地方:

  • 根据id查询商铺时,将数据库结果写入缓存时,需要设置超时时间。(超时剔除策略)
  • 根据id修改店铺时,先修改数据库,再删除缓存。

在ShopServiceImpl.java代码中设置超时时间:

stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);

修改店铺操作时,先修改数据库,再删除缓存:

    @Override
    @Transactional
    public 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();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1292022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WIFI7:O7851PM吞吐测试

近年来&#xff0c;随着科技的飞速发展&#xff0c;WIFI技术也在不断演进&#xff0c;从WIFI6逐渐过渡到WIFI6E&#xff0c;再到如今备受关注的WIFI7。这次我们将聚焦于我们欧飞信最新研发的WIFI7模组&#xff1a;O7851PM&#xff0c;通过对WIFI7的核心指标——吞吐量测试&…

IoT DC3 是一个基于 Spring Cloud 全开源物联网平台 linux docker部署傻瓜化步骤

如有不了解可先参考我的另一篇文章本地部署:IoT DC3 是一个基于 Spring Cloud 的开源的、分布式的物联网(IoT)平台本地部署步骤 如有不了解可先参考我的另一篇文章本地部署: 1 环境准备: JDK 8 以上 docker 安装好 下载docker-compose-dev.yml 文件 执行基础环境docker安装 …

如何使用技术 SEO 优化 Pinterest 富图钉

Pinterest 可以影响搜索引擎排名&#xff0c;尤其是谷歌。不过&#xff0c;它的作用方式与其他搜索引擎优化因素不同。这就是 Google 将图钉放在 nofollow 列表中。但是&#xff0c;它们仍然可以作为搜索引擎优化的一个重要因素。 高质量的图钉具有高分辨率的图片、吸引人的内…

【高数:1 映射与函数】

【高数&#xff1a;1 映射与函数】 例2.1 绝对值函数例2.2 符号函数例2.3 反函数表示例2.4 双曲正弦sinh&#xff0c;双曲余弦cosh&#xff0c;双曲正切tanh 参考书籍&#xff1a;毕文斌, 毛悦悦. Python漫游数学王国[M]. 北京&#xff1a;清华大学出版社&#xff0c;2022. 例2…

【Hung-Yi Lee】强化学习笔记

文章目录 What is RLPolicy GradientPolicy Gradient实际是怎么做的On-policy v.s. Off-policyExploration配音大师 Actor-Critic训练value function的方式网络设计DQN Reward ShapingNo Reward&#xff1a;Learning from Demonstration What is RL 定义一个策略网络&#xff0…

JM中ref_pic_list_modification bug记录

问题描述 今天在用JM对YUV420p编码时,发现编出的码流用ffplay播放花屏,报如下错误: JM的版本时19.1,没有使能B帧,PicOrderCntType设置为2,其它都是encoder.cfg中的默认配置。我用一些码流分析工具播放H264码流正常,用一些播放器播放也都存在花屏,不过大多数播放器都是…

Java程序员,你掌握了多线程吗?

文章目录 01 多线程对于Java的意义02 为什么Java工程师必须掌握多线程03 Java多线程使用方式04 如何学好Java多线程写作末尾 摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流…

word中如何插入公式,如何高效使用mathtype,遇到他人论文的复杂公式如何直接粘贴复制,为你一一答疑解惑!!

文章目录 一、论文中插入公式---最原始&#xff0c;最好用&#xff0c;最稳定的方法1.1 主页--插入---对象1.2 找到公式编辑器&#xff0c;对应你的版本1.3 直接输入公式&#xff0c;关闭界面 二、如何做好一个懒人——如何直接粘贴别人PDF等格式论文中的公式&#xff1f;2.1 使…

活动回顾|德州仪器嵌入式技术创新发展研讨会(上海站)成功举办,信驰达科技携手TI推动技术创新

2023年11月28日&#xff0c;德州仪器(TI)嵌入式技术创新发展研讨会在上海顺利举办。作为TI中国第三方IDH&#xff0c;深圳市信驰达科技有限公司受邀参加&#xff0c;并设置展位&#xff0c;展出CC2340系列低功耗蓝牙模块及TPMS、蓝牙数字钥匙解决方案&#xff0c;与众多业内伙伴…

种下一棵栀子花

女孩说自己是男孩当年伸手就可触及的栀子花.男孩沉默了,明白了当初失去了什么. 时光倒流,13年前的一个夏天夜晚,男孩与女孩同在沪城,女孩分享了自己的照片给男孩.男孩站在窗前,那晚的夜空很美丽,仿佛托着那个白衣裳女孩的纯真的梦,来到了自己的身边. 女孩说彼此间只是少了一个深…

017 OpenCV 向量机SVM

目录 一、环境 二、SVM原理 三、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、SVM原理 OpenCV中的向量机&#xff08;SVM&#xff09;是一种监督学习算法&#xff0c;用于分类和回归分析。它通过找到一个最优的超平…

优化AI机器人外呼之话术制作

智能语音机器人&#xff0c;OKCC-AI厂家制作话术工作实践总结。 一、 语音机器人话术制作&#xff0c;一般可以分为三个模块&#xff1a; 第一&#xff1a;是主干流程&#xff0c;也叫主流程 这个部分有点类似我们人工呼叫中心&#xff0c;常说的话术脚本。 第二&#xff1a…

如何处理3dmax渲染完成后阴影部分?

使用3dmax软件&#xff0c;对效果图进行渲染过程中&#xff0c;有不少小伙伴&#xff0c;在渲染完成后出现问题。 较为常见的3dmax渲染问题有3dmax渲染有阴影&#xff1f; 对于一些新手伙伴遇到这类问题&#xff0c;不知如何解决&#xff0c;就会苦恼3dmax渲染有阴影怎么办&am…

剑指Offer 从尾到头打印链表

目录 刷题链接&#xff1a;题目描述思路一&#xff1a;复杂度分析python3C 刷题链接&#xff1a; https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035 题目描述 输入一个链表的头节点&#xff0c;按链表从尾到头的顺序返回每个节点的值&#xff08;用数组返…

2024年AMC8考试报名的唯一途径和备考建议,别再浪费时间去探索

最近有些家长和孩子咨询六分成长2024年AMC8美国数学竞赛的报名和考试等事宜。 和他们交流&#xff0c;我发现很多家长和孩子走了许多弯路&#xff0c;被网上的信息带偏了&#xff0c;且浪费了很多时间。为此&#xff0c;六分成长将2024年AMC8报名和考试等的相关信息最新版&…

西南科技大学模拟电子技术实验六(BJT电压串联负反馈放大电路)预习报告

一、计算/设计过程 BJT电压串联负反馈放大电路图1-1-1-1为BJT电压串联负反馈放大实验电路,若需稳定输出电压,减小从信号源所取电流,可引入电压串联负反馈闭合开关。 图1-1-1-1 理论算法公式(1)闭环电压放大倍数 (2)反馈系数 (3)输入电阻 (4)输出电阻 计算过程。开环…

Java第二十一章 :网络通信

网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素封装成不同的类&#xff0c;用户只要创建这些类的对象&#xff0c;使用相应的方法&#xff0c;即使不具备有关的网络支持&#xff0c;也可以编写出高质量的网络通信程…

0009Java程序设计-ssm微信小程序在慢性疾病管理中的应用

文章目录 **摘要**目录系统实现开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 首先,论文一开始便是清楚的论述了小程序的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例…

1.1美术理论基础

一、光影 物体呈现在人们眼前的时候&#xff0c;不同的受光面其明暗变化以及物体的影子。 1.什么是黑白灰 在美术中黑白灰指亮面、灰面、暗面&#xff0c;属于素描的三大面&#xff0c;主要体验一个物体的整体寿光过程。普遍存在于各种艺术和设计领域。黑白灰作品的出现&#x…

C++ 的vector、array和数组的比较

相同点&#xff1a; 三者均可以使用下表运算符对元素进行操作&#xff0c;即vector和array都针对下标运算符[]进行了重载 三者在内存的方面都使用连续内存&#xff0c;即在vector和array的底层存储结构均使用数组 不同点&#xff1a; vector属于变长容器&#xff0c;即可以根…