首页 > 数据库 >Redis学习之缓存实现及缓存更新

Redis学习之缓存实现及缓存更新

时间:2023-09-20 16:55:23浏览次数:34  
标签:shop 缓存 数据库 Redis 更新 Result id

介绍

什么是缓存?

缓存就是数据交换的缓冲区(称作Cache [ kæʃ ] ),是存贮数据的临时地方,一般读写性能较高。

image-20230920162703243

为什么需要缓存?

提前准备好数据,便于更快地读写。

 

缓存是把双刃剑,要权衡利弊。

优点:降低后端负载

提高读写效率,降低响应时间

缺点:数据一致性成本 代码维护成本 运维成本

 

实现

关键流程

1.暂无缓存,从数据库读,然后设置(更新)缓存

2.已有缓存,直接读缓存

image-20230920163238784

代码示例

ShopController

    /**
     * 根据id查询商铺信息
     * @param id 商铺id
     * @return 商铺详情数据
     */
    @GetMapping("/{id}")
    public Result queryShopById(@PathVariable("id") Long id)    {
        return shopService.queryById(id);
    }

ShopServiceImpl

    @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);
        }
        // 判断命中的是否是空值
        if (shopJson != null) {
            // 返回一个错误信息
            return Result.fail("店铺不存在!");
        }
        // 4.不存在,根据id查询数据库
        Shop shop = getById(id);
        if (shop == null){
            // 将空值写入redis
            stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);
            // 5.不存在返回错误
            return Result.fail("店铺不存在!");
        }
        // 6.存在,写入redis
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
        // 7.返回
        return Result.ok(shop);
    }

 

缓存更新

几种常用策略,一般会选择主动更新+超时提出兜底。

image-20230920163649109

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

用户使用缓存中的过时数据,就会产生类似多线程数据安全问题,从而影响业务,产品口碑等

主动更新缓存的几种方式

1.Cache Aside Pattern 人工编码方式:缓存调用者在更新完数据库后再去更新缓存,也称之为双写方案。(以数据库的数据为准,业务层自己来控制缓存的写入)

2.Read/Write Through Pattern : 由系统本身完成,数据库与缓存的问题交由系统本身去处理.(使用现成的数据写入服务,让服务来维护数据库和缓存的一致性,我门只用写数据即可)

3.Write Behind Caching Pattern :调用者只操作缓存,其他线程去异步处理数据库,实现最终一致。(先更新缓存,通过异步线程定期将缓存的数据持久化(同步道数据库中))

 

操作缓存和数据库时有三个问题需要考虑: 1.删除缓存还是更新缓存? 更新缓存:每次更新数据库都更新缓存,无效写操作较多 删除缓存:更新数据库时让缓存失效,查询时再更新缓存

2.多线程情况下,如何保证缓存与数据库的操作的同时成功或失败? 1.单体系统:将缓存与数据库操作放在一个事务 2.分布式系统:利用TCC等分布式事务方案

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

下图为两种方式在多线程下可能出现的问题

image-20230920164323279

两种方式都不能百分百保证一致性,但【先操作数据库,再删除缓存】,出现问题的几率低,可以配合延时双删保证缓存一定被删除。

实现

核心思路如下:

修改ShopController中的业务逻辑,满足下面的需求:

根据id查询店铺时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间

根据id修改店铺时,先修改数据库,再删除缓存

修改重点代码1:修改ShopServiceImpl的queryById方法

设置redis缓存时添加过期时间

image-20230920164604030

修改重点代码2

代码分析:通过之前的淘汰,我们确定了采用删除策略,来解决双写问题,当我们修改了数据之后,然后把缓存中的数据进行删除,查询时发现缓存中没有数据,则会从mysql中加载最新的数据,从而避免数据库和缓存不一致的问题

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

标签:shop,缓存,数据库,Redis,更新,Result,id
From: https://www.cnblogs.com/ysk0904/p/17717756.html

相关文章

  • Redis 面试常见问答
    本文出自:https://thinkinjava.cn作者:莫那鲁道1\.什么是缓存雪崩?怎么解决?一般而言,我们会利用缓存来缓冲对数据库的冲击,假如缓存无法正常工作,所有的请求便会直接发送至数据库,进而导致数据库崩溃,从而导致整个系统崩溃。如何解决呢?2种策略(同时使用):对缓存做高可用,防止缓存宕机使用断......
  • Redis的五中数据类型以及应用场景
    1.string字符串在redis中string是可以修改de被称之为动态字符串.其中内部更像arraylist内部维护一个字节数组,在其内部分配了一定的空间.内存分配机制当字符串的长度小于1m的时候,每次扩容都是加倍空间当字符串长度超过1m的时候每次扩容只会扩张1m的空间字符串的最大长度......
  • Redis之Sentinel哨兵监控
    哨兵简介 1.redis提供了哨兵的命令,是一个独立的进程 2.哨兵通过发送命令给节点,通过redis节点响应达到监控多个redis实例的运行情况 3.当哨兵发现master宕机,会自动将从节点切换成主节点,并通知其他的从节点,修改配置文件切换主机 4.默认端口是26379哨兵的主要任务 1.......
  • Redis 不同插入方法的性能对比
    1.测试目的对比Redis不同插入方法(插入同时能设置过期时间)的性能区别。2.测试数据key:SMGP_value:JSON数据{ "spName":"100003", "protocol":"SMGP", "remoteAddress":"192.192.192.192:44192", "host":"192.192......
  • redis
    前言原文作者:KyleViolet文章链接:Redis入门|Kyle'sBlog(cyborg2077.github.io)版权声明:本博客所有文章除特别声明外,均采用CCBY-NC-SA4.0许可协议。转载请注明来自Kyle'sBlog!本文章为在原文基础上,进行稍作修改的文章,版权声明如上。本文为瑞吉外卖项目的后续......
  • Mysql中如何批量更新数据库中某个字段值中的部分内容;
    在平时的开发过程中,偶尔会遇到需要批量更新数据库中某个字段值的部分内容,比如某个字段存储的是图片的URL路径,这个路径中的域名无法访问了,需要更新为另一个ip地址。Mysql中提供了REPLACE函数:可以使用了REPLACE函数来替换原来字段中的一部分数据为新值。UPDATEcar_data_hisSETc......
  • Redis 面试常见问答
    本文出自:https://thinkinjava.cn作者:莫那鲁道1.什么是缓存雪崩?怎么解决?一般而言,我们会利用缓存来缓冲对数据库的冲击,假如缓存无法正常工作,所有的请求便会直接发送至数据库,进而导致数据库崩溃,从而导致整个系统崩溃。如何解决呢?2种策略(同时使用):对缓存做高可用,防止缓......
  • 关闭MyEclipse7.0自动更新 + 优化启动
    关闭MyEclipse7.0自动更新+优化启动1.window-->preferences-->General-->StartupandShutdown-->在列表中找到"AutomaticUpdatesScheduler"项去掉前面的勾。2.Window-->Preferences-->MyeclipseEnterpriseWorkbench-->Maven4Myeclipse-->......
  • 麒麟系统常见问题汇总(持续更新版)
    麒麟系统的软件商店自动更新问题麒麟系统安装Python3.9麒麟系统安装Typora......
  • dns缓存中毒43.227.199.x
    什么是DNS缓存中毒DNS缓存中毒是一种网络攻击,它使您的计算机误以为它会到达正确的地址,但事实并非如此。攻击者使用DNS缓存中毒来劫持互联网流量并窃取用户凭据或个人数据。DNS缓存中毒攻击也称为DNS欺骗,它试图诱骗用户将其私人数据输入不安全的网站。什么是DNS缓存在讨论攻击之......