20.缓存的更新策略

news2024/12/29 17:35:59

定义

缓存中的旧数据与数据库不一致。

缓存更新策略的类型

1.内存淘汰,利用redis的内存淘汰机制,当内存不足时自动淘汰部分数据。下次查询时更新缓存。redis默认开启了此机制。这种保证数据的一致性差。

2.超时剔除,给缓存数据添加TTL时间,到期后自动删除缓存,下次查询时更新缓存。一致性一般。

3.主动更新,自己编写业务逻辑,在修改数据库的同时更新缓存。一致性好。

根据业务场景选择

1.低一致性需求,可以使用内存淘汰机制。例如店铺类型的查询的缓存。

2.高一致性需求,主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存。

主动更新策略

1.由缓存的调用者,在更新数据库的同时更新缓存(推荐)

2.缓存和数据库做为一个服务,由服务来维护一致性。调用者调用该服务,无需关心缓存的一致性问题。

3.调用者只操作缓存,由其他线程异步的将缓存数据持久化到数据库,保证最终一致。(好处:如果对缓存做了多次更新操作,只需要将最后一次更新操作同步到数据库,提升了性能。缺点:如果一段时间内对缓存执行了上千次操作还没来得及将数据同步到数据库,那么这一段时间缓存与数据库的数据是不一致的。所以可靠性和一致性都会存在问题。)

更新数据库的同时更新缓存

需要注意的考虑的问题

1.删除缓存还是更新缓存?

更新缓存:每次更新数据库都要更新缓存,无效写操作太多。

删除缓存:更新数据库时让缓存失效,查询时再更新缓存。(推荐)

2.如果保证缓存和数据库操作的同时成功和同时失败?

单体项目:将缓存和数据库操作放在一个事务中。

分布式系统:利用TCC等分布式事务方案。

3.先操作缓存还是先操作数据库?

先删缓存,再操作数据库

考虑多线程情况下的特殊情况:线程一删除缓存后,还没来得即更新数据库中的数据。此时线程来了发现缓存中没有数据就查询数据库然后将数据写回缓存。然后线程1才执行更新数据库的操作,就造成了缓存和数据库数据的不一致。这种情况发生的概率高,因为线程一删除缓存很快,更新数据库很慢。 线程二查询缓存、查询数据库、写入缓存操作都很快。

先操作数据库,再删除缓存

这种情况发生的概率很低。

满足一些条件:

1.多个线程并行进行。

2.其中一个线程查询数据的时候,恰好缓存失效。同时会去查询数据库并将数据写入缓存。这些操作都很快,都在微妙级别。就在查询数据库和写入缓存之间,突然来了一个线程先去更新数据库,然后删除缓存。更新数据库肯定比较慢的。所以这种情况的可能性极低。因为缓存的写速度远远大于对数据库的操作。

3.发生概率低,不代表不会发生。万一发生了,我们可以给缓存设置一个超时时间,过一段时间,缓存数据失效,就会跟数据库中的数据保持一致。超时剔除作为兜底方案。

读操作

缓存命中则直接返回,缓存未命中则查数据库,并写入缓存,设定超时时间。

写操作

先写数据库,然后再删除缓存。确保数据库与缓存操作的原子性。

@Override
    public Result queryById(Long id) {
        String key = RedisConstants.CACHE_SHOP_KEY + id;
        //从redis中查询商铺缓存
        String shopJsonStr = stringRedisTemplate.opsForValue().get(key);
        //redis中有数据直接返回
        if(StrUtil.isNotBlank(shopJsonStr)) {
            Shop shop = JSONUtil.toBean(shopJsonStr, Shop.class);
            return Result.ok(shop);
        }
        //redis中没有数据,继续查询数据库
        Shop shop = getById(id);
        if(ObjectUtil.isNull(shop)) {
            //数据库没有查询到数据,返回错误
            return Result.fail("店铺不存在");
        }
        //数据库中查询到数据,存入redis,再返回数据;设置超时时间
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
        return Result.ok(shop);
    }

读操作设置超时时间

@Override
    @Transactional
    public Result updateShop(Shop shop) {
        if(shop.getId() == null) {
            return Result.fail("店铺id不能为空,更新失败");
        }
        //1.更新数据库
        updateById(shop);
        //2.删除缓存
        stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + shop.getId());
        return Result.ok();
    }

{

    "id":1,

    "area":"北京",

    "openHours":"10:00-22:00",

    "sold":4215,

    "address":"北京王府井19号",

    "comments": 3035,

    "avgPrice": 80,

    "score": 37,

    "name": "画画茶餐厅",

    "typeId": 1 

}

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

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

相关文章

保证MQ的高可用性:RabbitMQ为例

保证MQ的高可用性:RabbitMQ为例 一、单机模式二、普通集群模式三、镜像集群模式 💖The Begin💖点点关注,收藏不迷路💖 消息队列(MQ)在软件开发中至关重要,其高可用性关乎系统稳定。R…

48、Python之模块和包:当导入模块时,Python解释器做了什么

引言 上一篇文章中,我们简单介绍了各种导入模块的方法,并通过代码演示了模块被导入之前的模块查找的路径解析过程,但是,只是局限在了加载模块之前。 今天这篇文章,打算把整个模块导入的全流程进行梳理,从…

Windows上传Linux文件行尾符转换

Windows上传Linux文件行尾符转换 1、Windows与Linux文件行尾符2、Windows与Linux文件格式转换 1、Windows与Linux文件行尾符 众所周知,Windows、Mac与Linux三种系统的文件行尾符不同,其中 Windows文件行尾符(\r\n): L…

【初阶数据结构题目】40. 计数排序

计数排序 计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤: 统计相同元素出现次数 根据统计的结果将序列回收到原来的序列中 思路: 例如:{6,1,2,9,4,…

书生模型实战L1---OpenCompass 评测

书生模型实战系列文章目录 第一章 入门岛L0(Linux) 第二章 入门岛L0(python) 第三章 入门岛L0(Git) 第四章 基础岛L1(书生全链路开源介绍) 第五章 基础岛L1(Demo&#x…

【计算机三级-数据库技术】操作题大题(第六套)

第六套操作题 第46题 假定要建立一个学校科研项目管理的信息系统,需要管理如下信息: 教师:教师编号、教师姓名; 项目:项目编号、项目名称、资助额: 学生:学生编号、学生姓名、学位&#xff0c…

Spring底层机制环境搭建

文章目录 1.模块创建和依赖引入1.聚合模块,下面有一个myspring2.查看父模块是否管理了子模块3.myspring模块引入基本包 2.进行环境搭建1.目录概览2.UserController.java3.UserService.java4.UserDao.java5.AppMain.java6.beans.xml7.测试8.配置UserController.java为…

教程3_单元层次结构1

单元层次结构是指通过将多个单元嵌套使用,形成具有层次结构的设计。每个单元可以包含其他单元的实例,这些实例称为“子单元”,而包含这些子单元的单元称为“父单元”。这种结构使得复杂设计变得模块化和可复用。 1、创建并使用单元实例 创建…

解读电子看板如何助力线缆行业目视化改革

线缆行业作为国民经济的重要组成部分,其生产过程复杂,环节众多,对生产效率和质量控制有着严格的要求。传统的管理方式往往难以满足现代化生产的需求,而电子看板的引入,为线缆行业带来了全新的管理理念和模式&#xff0…

23.合并K个升序链表-----力扣

一、题目: 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 题目链接 二、示例: 输入:lists [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释…

​元宇宙虚拟展厅如何搭建?制作​线上虚拟展厅的成本

电子商务热潮的日益普及,让更多企业开始寻找具有创新性的方式来向客户展示他们的产品和服务。而元宇宙中的虚拟展厅也为企业提供了一个独特的机会,作为帮助企业展示其产品和服务特色的平台,元宇宙越发地受欢迎。不过在元宇宙中制作虚拟展厅的…

自带灭火电池?深蓝SL03托底事故揭秘

近日,网络上的一段热传视频,让不少网友看得先是惊心动魄,然后却又啧啧称奇。 该视频显示,8月18日晚上19点28分,一辆深蓝SL03在行驶中意外遭遇严重托底事故,车辆瞬间腾空跳跃,紧接着底盘出现明火…

【状态模式】设计模式系列:理解与实践(详细解读)

文章目录 状态模式详解:理解与实践1. 引言2. 状态模式简介2.1 定义2.2 应用场景2.3 与其他模式的关系 3. 状态模式的基本概念3.1 上下文(Context)类的角色3.2 状态(State)接口/抽象类3.3 具体状态(Concrete State)类3.4 UML类图和时序图 4. 状态模式的工作原理4.1 如…

用Python解决预测问题_多元线性回归模板

多元线性回归是一种统计学方法,用于分析两个或多个自变量(解释变量)与一个因变量(响应变量)之间的关系。在最简单的线性回归模型中,只有一个自变量和一个因变量,它们之间的关系可以用一条直线来…

Java对象的内存结构

文章目录 概述1. 对象头 (Header)Mark Word1. 32位HotSpot虚拟机中的MarkWord2. 64位HotSpot虚拟机中的MarkWord Class PointerArray Length指针压缩原理指针压缩测试 2. 实例数据 (Instance Data)3. 填充数据 (Padding Data) 查看 Java 对象的内存结构使用反射和VisualVM、JCo…

linux下的oracle启动命令

一、服务器断电后,手工启动oracle数据库步骤如下: 1、进入数据库服务器,切换到oracle用户,命令:su - oracle 2、启动数据库,命令: 1) sqlplus / as sysdba 2) startup 3)如果数据库已…

Rabbit mq 虚拟机stop无法重启

之前从后台进去&#xff0c;这个地方死活无法重启 然后重启docker 以及mq都不行 docker exec -it <CONTAINER_ID_OR_NAME> /bin/bash rabbitmqctl stop_app rabbitmqctl start_app 最后删除虚拟机&#xff0c;然后重建就行了 rabbitmqctl delete_vhost / rabbitmqctl…

C++ | Leetcode C++题解之第365题水壶问题

题目&#xff1a; 题解&#xff1a; class Solution { public:bool canMeasureWater(int x, int y, int z) {if (x y < z) {return false;}if (x 0 || y 0) {return z 0 || x y z;}return z % gcd(x, y) 0;} };

iPhone设备使用技巧:忘记密码的情况下如何解除iOS 18/17屏幕时间

我们给了儿子一部新手机。在尝试擦除旧手机上的所有内容并恢复出厂设置时&#xff0c;它要求提供 4 位屏幕时间密码。我已经尝试了我们会使用的所有可能性&#xff0c;但无法弄清楚。我们如何绕过这个问题或将手机恢复出厂设置以便我们可以出售它&#xff1f; Apple 社区 对于…

小琳AI课堂:Langchain

大家好&#xff0c;这里是小琳AI课堂&#xff0c;今天我们要探索一个令人兴奋的AI新概念——Langchain。 想象一下&#xff0c;如果我们可以把强大的大型语言模型&#xff0c;比如GPT-3&#xff0c;像乐高积木一样组合起来&#xff0c;会怎么样&#xff1f;这就是Langchain的核…