Redis数据缓存

这篇具有很好参考价值的文章主要介绍了Redis数据缓存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

缓存

一 缓存基础

1 缓存的概念和作用

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

Redis数据缓存,缓存,redis,数据库

2 缓存的使用

之前没有使用缓存是的模型

Redis数据缓存,缓存,redis,数据库

3 项目说明

Redis数据缓存,缓存,redis,数据库

当我们查询商家信息的时候,直接从mysql中获取的。现在我们将原来的项目改造。改造地方在ShopController,我们按照流程图去做,添加redis缓存,业务都是在service中实现的。

# 具体实现流程
1 redis中查询商户缓存
2 判断是否存在
3 存在直接返回
4 不存在根据id去数据库查询
5 数据库也不存在,返回错误
6 存在则写入redis中
7 返回
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>
1 修改controller
/**
    * 根据id查询商铺信息
     * @param id 商铺id
     * @return 商铺详情数据
*/
@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {
    return shopService.queryById(id);
    //        return Result.ok(shopService.getById(id));
}
2 修改service
@Resource
private RedisTemplate<String,Object> redisTemplate;
​
@Override
public Result queryById(Long id) {
    //1 redis中查询商户缓存
    String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);
    //2 判断是否存在
    if(StrUtil.isNotBlank(shopJson)){
        //3存在直接返回
        Shop shop = JSONUtil.toBean(shopJson, Shop.class);
        return Result.ok(shop);
    }
    //4 不存在根据id去数据库查询
    Shop shop = this.getById(id);
    //5 数据库也不存在,返回错误
    if(shop==null){
        return Result.fail("店铺不存在");
    }
    //6 存在则写入redis中
    redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop));
    //7 返回
    return Result.ok(shop);
}
3 改造首页

Redis数据缓存,缓存,redis,数据库

@Autowired
private RedisTemplate<String, Object> redisTemplate;
​
@Override
public Result queryTypeList() {
​
    List<Object> list = redisTemplate.opsForList().range("cache.list",0,-1);
    if(list!=null && list.size()!=0){
        return Result.ok(list);
    }
    List<ShopType> sort = this.query().orderByAsc("sort").list();
    if(sort==null||sort.size()==0){
        return Result.fail("列表不存在");
    }
    sort.forEach(s->redisTemplate.opsForList().rightPush("cache.list",s));
    return Result.ok(sort);
}

二 数据一致性

1 思路

  • 查询数据的时候,如果缓存未命中,则查询数据库,将数据写入缓存设置超时时间

  • 修改数据时,先修改数据库,在删除缓存。

  • 延时双删策略

2 代码实现

  • 修改更新方法,添加超时时间

 @Override
    public Result queryById(Long id) {
        //1 redis中查询商户缓存
        String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);
        //2 判断是否存在
        if(StrUtil.isNotBlank(shopJson)){
            //3存在直接返回
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        //4 不存在根据id去数据库查询
        Shop shop = this.getById(id);
        //5 数据库也不存在,返回错误
        if(shop==null){
            return Result.fail("店铺不存在");
        }
        //6 存在则写入redis中
       redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);
        //7 返回
        return Result.ok(shop);
    }
  • 修改ShopController

  
@PutMapping
    public Result updateShop(@RequestBody Shop shop) {
        // 写入数据库
​
        //shopService.updateById(shop);
        //return Result.ok();
        return  shopService.update(shop);
    }
  • 修改service代码 延时双删策略

 @Override
    public Result update(Shop shop) {
​
        Long id = shop.getId();
        if(id==null){
            return Result.fail("店铺id不存在");
        }
         // 删除缓存
        redisTemplate.delete("cache.shop:" + id);
        // 更新数据库
        updateById(shop);
        Thread.sleep(800);
        // 删除缓存
        redisTemplate.delete("cache.shop:" + id);
        return Result.ok();
    }

3 修改完代码以后,将所有的缓存删除,执行查询操作,多了超时

Redis数据缓存,缓存,redis,数据库

4 用postman执行修改方法: localhost:8081/shop

{
  "area":"大关",
  "sold":3035,
  "address":"金华路锦昌文华苑29号",
  "name":"102茶餐厅",
  "x":120.149192,
  "y":30.316078,
  "typeId":1,
  "id":1
}

Redis数据缓存,缓存,redis,数据库

执行完成以后,数据库的数据发生改变,查看redis的数据已经删除了。

三 缓存常见问题

1 缓存穿透:

客户端请求的数据,在数据库和redis中都不存在,这样缓存永远都不会生效,请求最终都到了数据库上。

解决方案:

  • 当在数据库查询的结果也不存在的时候,可以返回null值给redis,并且设置TTL

Redis数据缓存,缓存,redis,数据库

  • 布隆过滤器

    Redis数据缓存,缓存,redis,数据库

布隆过滤器是一种数据结构,底层是位数组,通过将集合中的元素多次hash得到的结果保存到布隆过滤器中。主要作用就是可以快速判断一个元素是否在集合里面,但是因为算法的原因,也有一定概率的错误。

开发的时候我们一般选择空值值方式。

  • 代码方式实现

    Redis数据缓存,缓存,redis,数据库

根据id查询的时候,如果信息不存在,则要将空值写入redis,并设置空值过期时间

@Override
    public Result queryById(Long id) {
        //1 redis中查询商户缓存
        String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);
        //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 = this.getById(id);
        //5 数据库也不存在,返回错误
        if(shop==null){
            // 空值写入redis中
            redisTemplate.opsForValue().set("cache.shop:" + id,"",3, TimeUnit.MINUTES);
            return Result.fail("店铺不存在");
        }
        //6 存在则写入redis中
       redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);
        //7 返回
        return Result.ok(shop);
    }

2 缓存击穿:

也叫热点key问题,一个被高并发访问且业务复杂的key突然失效了,无数的请求瞬间给数据库带来的巨大冲击

Redis数据缓存,缓存,redis,数据库

解决方案: 互斥锁 逻辑过期

Redis数据缓存,缓存,redis,数据库

互斥锁思路:

Redis数据缓存,缓存,redis,数据库

查询缓存的时候,未命中需要获取锁 代码ShopServiceImpl

@Override
public Result queryById(Long id) {
    //1 redis中查询商户缓存
    String shopJson = (String)redisTemplate.opsForValue().get("cache.shop:" + id);
    //2 判断是否存在
    if(StrUtil.isNotBlank(shopJson)){
        //3存在直接返回
        Shop shop = JSONUtil.toBean(shopJson, Shop.class);
        return Result.ok(shop);
    }
    if(shopJson!=null){
        return Result.fail("店铺不存在");
    }
    Shop shop = null;
    String lockKey = "lock.id:" + id;
    try {
        //代码到这里说明没有命中缓存,那么就可以获取锁了
        boolean isLock = tryLock(lockKey);
        // 如果没有拿到锁,则等待一会,递归执行代码
        if(!isLock){
            Thread.sleep(100);
            queryById(id);
        }
        //获取锁成功
        //4 不存在根据id去数据库查询
        shop = this.getById(id);
        //5 数据库也不存在,返回错误
        if(shop==null){
            // 空值写入redis中
            redisTemplate.opsForValue().set("cache.shop:" + id,"",3, TimeUnit.MINUTES);
            return Result.fail("店铺不存在");
        }
        //6 存在则写入redis中
        redisTemplate.opsForValue().set("cache.shop:" + id,JSONUtil.toJsonStr(shop),30, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        unlock(lockKey);
    }
    //7 返回
    return Result.ok(shop);
}

    // 获取锁
private boolean tryLock(String key){
    Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
    return BooleanUtil.isTrue(flag);
}
//释放锁
private void unlock(String key){
    redisTemplate.delete(key);
}

3 缓存雪崩

同一时间段内,大量的缓存key失效或者redis宕机,到时大量的请求到达数据库,带来巨大的压力。

Redis数据缓存,缓存,redis,数据库

解决方案

  • 给key设置随机的TTL

  • 集群方案防止宕机不可用文章来源地址https://www.toymoban.com/news/detail-796281.html

到了这里,关于Redis数据缓存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis如何保证缓存和数据库一致性?

    现在我们在面向增删改查开发时,数据库数据量大时或者对响应要求较快,我们就需要用到Redis来拿取数据。 Redis:是一种高性能的内存数据库,它将数据以键值对的形式存储在内存中,具有读写速度快、支持多种数据类型、原子性操作、丰富的特性等优势。 优势: 性能极高

    2024年01月16日
    浏览(70)
  • Redis---数据库和缓存如何保证一致性?

    用「读 + 写」请求的并发的场景来分析: 假如某个用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存

    2024年01月24日
    浏览(57)
  • Redis如何保障缓存与数据库的数据一致性问题?

    目录 一.最经典的数据库加缓存的双写双删模式 二. 高并发场景下的缓存+数据库双写不一致问题分析与解决方案设计 三、上面高并发的场景下,该解决方案要注意的问题 1.1 Cache Aside Pattern概念以及读写逻辑 (1)读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取

    2023年04月21日
    浏览(49)
  • 数据库缓存服务——NoSQL之Redis配置与优化

    目录 一、缓存概念 1.1 系统缓存 1.2 缓存保存位置及分层结构 1.2.1 DNS缓存 1.2.2 应用层缓存 1.2.3 数据层缓存 1.2.4 硬件缓存 二、关系型数据库与非关系型数据库 2.1 关系型数据库 2.2 非关系型数据库 2.3 关系型数据库和非关系型数据库区别: 2.4 非关系型数据库产生背景 2.5 总结

    2024年02月15日
    浏览(50)
  • Redis数据库 | 发布订阅、主从复制、哨兵模式、缓存雪崩

    💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息 Redis 客户端可以订阅任意数量的频道 Redis主从复制是指在Redis中设置一个主节点(Master)和一个或多个从节点(Slave),

    2024年02月15日
    浏览(57)
  • Springboot+Redis:实现缓存 减少对数据库的压力

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 Redis实战与进阶 本专栏讲解Redis从原理到实践 这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn.net/   目录 缓存如何实现?

    2024年03月24日
    浏览(59)
  • redis面试题目-如何保证数据库与缓存的数据一致性

    原视频:https://www.bilibili.com/video/BV1Km4y1r75f?p=62vd_source=fa75329ae3880aa55609265a0e9f5d34 由于缓存和数据库是分开的,无法做到原子性的同时进行数据修改,可能出现缓存更新失败,或者数据库更新失败的情况,这时候会出现数据不一致,影响前端业务 先更新数据库,再更新缓存。缓

    2024年02月05日
    浏览(64)
  • Redis缓存MySQL数据库存储二者如何保证数据一致性

    在大型互联网应用中,由于数据库读写频繁、压力大等原因,我们通常会使用缓存来减少数据库的访问次数,提高系统的性能。而Redis作为一个高性能的内存数据库,成为了缓存的首选方案之一。但是,缓存和数据库之间存在数据一致性的问题,如何解决这个问题呢?本文将

    2023年04月19日
    浏览(52)
  • 如何保证Redis缓存和数据库的一致性问题

    熟练掌握Redis缓存技术? 那么请问Redis缓存中有几种读写策略,又是如何保证与数据库的一致性问题 今天来聊一聊常用的三种缓存读写策略 首先我们来思考一个问题 写 先更新缓存 再更新数据库 首先如果缓存更新成功但数据库更新失败,会导致数据不一致的问题 其次当请求

    2024年02月14日
    浏览(51)
  • Redis 缓存与数据库双写不一致如何解决

    Redis缓存与数据库双写不一致是一个常见的挑战,但可以通过一些方法来解决或减轻这种不一致性。以下是一些可能的解决方案: 事务处理: 在进行缓存和数据库双写时,确保它们被包含在同一事务中。这可以通过使用支持事务的数据库和Redis事务来实现。这样,要么两者同

    2024年01月21日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包