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

2023.12.7

redis实现商户查询缓存

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

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

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

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic 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 {@Resourceprivate 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 {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic 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@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();}

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

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

相关文章

python中时间戳与时间字符的相互转换

1.获取时间的方法 使用的是time模块 import time time1 time.time() # time1: 1701934920.676534 timestruct time.localtime(time1) # timestruct: time.struct_time(tm_year2023, tm_mon12, tm_mday7, tm_hour15, tm_min42, tm_sec0, tm_wday3, tm_yday341, tm_isdst0)2.…

Apache Hive(部署+SQL+FineBI构建展示)

Hive架构 Hive部署 VMware虚拟机部署 一、在node1节点安装mysql数据库 二、配置Hadoop 三、下载 解压Hive 四、提供mysql Driver驱动 五、配置Hive 六、初始化元数据库 七、启动Hive(Hadoop用户) chown -R hadoop:hadoop apache-hive-3.1.3-bin hive 阿里云部…

【STM32单片机】简易电子琴设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用数码管模块、矩阵按键、无源蜂鸣器等。 主要功能&#xff1a; 系统运行后&#xff0c;蜂鸣器播放一首音乐&#xff0c;进入电子琴模式&#xff0c;…

无公网IP环境Windows系统使用VNC远程连接Deepin桌面

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

MySQL Connector/J 数据库连接 URL的语法

详情请参考&#xff1a;https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html jdbc:mysql:是用于普通的、基本的故障转移连接使用&#xff1a; jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][propertyValue1]…

联想范建平:联想混合AI架构具备两大明显优势

12月7日&#xff0c;首届AI PC创新论坛在北京联想集团总部举办。联想集团副总裁、联想研究院人工智能实验室负责人范建平表示&#xff0c;为提供真正可信、个性化的AI专属服务&#xff0c;联想提出了混合智能&#xff08;Hybrid AI&#xff09;概念&#xff0c;并已经显现出更强…

thinkphp 多表连接 子查询 group by 分组以最新的一条数据为组

用这个 $subQuery Db::name(wms_orderitems)->distinct(true)->field(kw_id,orders_id,product_id)->order(items_id desc)->buildSql();$list Db::name(wms_orders)->alias(order)->join($subQuery. item,item.orders_idorder.orders_id)->field(order…

【AntDB 数据库】国产分布式数据库发展趋势与难点

引言&#xff1a; 日前&#xff0c;为更好地满足亚信科技客户对于数据管理的需求&#xff0c;提高通用型数据库的产品服务能力与业务拓展能力&#xff0c;亚信科技分布式数据库AntDB发布V7.0版本产品&#xff0c;助力运营商核心系统实现全方位的自主可控与业务系统的平稳上线。…

搭建部署Hadoop2.x和3.x的区别

文章目录 2.x 和 3.x 的区别Java最小支持版本常用的端口号配置文件Classpath隔离NodeManager重连 进入官网自行查阅 2.x 和 3.x 的区别 Java最小支持版本 Hadoop 2.x&#xff1a;2.7 版本需要 Java 7&#xff0c;2.6 以及更早期版本支持 Java 6Hadoop 3.x&#xff1a;最低要求…

配置BFD状态与接口状态联动示例

BFD简介 定义 双向转发检测BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是一种全网统一的检测机制&#xff0c;用于快速检测、监控网络中链路或者IP路由的转发连通状况。 目的 为了减小设备故障对业务的影响&#xff0c;提高网络的可靠性&#xff0c;网…

深度学习实战65-人脸检测模型LFFD的搭建,LFFD模型的架构与原理的详细介绍

大家好,我是微学AI,今天给大家介绍一下深度学习实战65-人脸检测模型LFFD的搭建,LFFD模型的架构与原理的详细介绍。LFFD(Light and Fast Face Detector)模型是一种用于人脸检测的深度学习模型,其设计旨在实现轻量级和快速的人脸检测。本文将详细介绍LFFD模型的定义、优点、原…

【Linux】进程见通信之匿名管道pipe

1.匿名管道的特点 以下管道的统称仅代表匿名管道。 管道是一个只能单向通信的通信信道。为了实现进程间通信.管道是面向字节流的。仅限于父子通信或者具有血缘关系的进程进行进程见通信。管道自带同步机制&#xff0c;原子性写入。管道的生命周期是随进程的。 2.匿名管道通信…

SpringSecurity(五)

深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式&#xff0c;也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息&#xff0c;但是在SpringBoot项目中&#xff0c;我们慢慢脱离…

Java零基础——RocketMQ篇

1.RocketMQ简介 官网&#xff1a; http://rocketmq.apache.org/ RocketMQ是阿里巴巴2016年MQ中间件&#xff0c;使用Java语言开发&#xff0c;RocketMQ 是一款开源的分布式消息系统&#xff0c;基于高可用分布式集群技术&#xff0c;提供低延时的、高可靠的消息发布与订阅服…

03_阿里云_配置OSS环境变量

关于aliyunOSS文件上传的系统变量配置 问题引出 在黑马程序员2023新版JavaWeb开发教程教程中&#xff0c;P148Day11-04. 案例-文件上传-阿里云OSS-准备到P150Day11-06. 案例-文件上传-阿里云OSS-集成阿里云给的参考代码已经更新了&#xff0c;需要配置阿里云的用户变量&#…

K8S 删除命令空间时 一直卡住怎么办?

当使用完一个命名空间后&#xff0c;想删除了又删除不掉&#xff0c;这个时候查看命名空间的状态一直是Terminating。使用强制删除&#xff0c;也是还是不行。&#xff08;找了好多办法都不行&#xff09; [rootk8s-master kubernetes-yaml]# kubectl delete ns mem-example Er…

各种滤波算法的比较(GF、KF、EKF、UKF、PF)

目录 一、前言 二、滤波算法介绍 1、GF&#xff08;高斯滤波&#xff09; 2、KF&#xff08;卡尔曼滤波&#xff09; 3、EKF&#xff08;可扩展卡尔曼滤波&#xff09; 4、UKF&#xff08;无迹卡尔曼滤波&#xff09; 5、PF&#xff08;粒子滤波&#xff09; 三、不同滤…

elementui中添加开关控制

<template><!-- 图层管理 --><div class"home-wrapper"><div class"table-list"><div class"list"><el-table :data"tableData" height"100%" style"width: 100%;" border>&…

数字营销影响消费者行为的 6 种方式

如果您正在考虑转向在线市场&#xff0c;那么这个决定就好了&#xff01;没有什么比数字营销更强大的了。但是&#xff0c;在开始之前&#xff0c;请了解数字营销如何影响消费者行为。由于客户是任何企业的基石&#xff0c;因此跟踪消费者行为至关重要。 数据分析在识别潜在客…

3DMAX UV贴图修改插件安装卸载方法

3DMAX UV贴图修改插件安装卸载方法 3dMax贴图修改插件PolyUnwrapper是为纹理艺术家设计的一整套专业工具&#xff0c;尤其适用于建筑和游戏行业。 它包含许多功能&#xff0c;将大大帮助您改进UV展开的工作流程。 【主要功能特点】 -多重缝合。一次缝合多个壳 -自定义打包算…