Redis4-添加缓存、更新策略、缓存穿透、雪崩、击穿、缓存工具封装

本文详细介绍了Redis缓存的使用,包括缓存的作用、添加Redis缓存的方法、缓存更新策略(主动更新与先操作数据库再删除缓存)以及其可能导致的数据一致性问题。深入讨论了缓存穿透问题及其解决方案,如缓存空对象和布隆过滤器。接着分析了缓存雪崩的原因和对策,如添加随机TTL和采用Redis集群提高可用性。缓存击穿问题及解决方案,如互斥锁和逻辑过期时间。最后,提出了一种基于StringRedisTemplate的缓存工具类封装,用于处理缓存的多种场景需求。
摘要由CSDN通过智能技术生成

一、什么是缓存

缓存就是数据交换的缓冲区,cache,是存储数据的临时地方,一般读写性能较高

缓存的作用:

  • 降低后端负端,省去磁盘操作
  • 提高读写效率,降低响应时间(高并发问题)

缓存成本:

  • 数据一致性成本(DB数据变了,缓存没变,数据就不一致了)
  • 代码维护成本提高(解决一致性等)
  • 运维成本

二、添加Redis缓存

1、代码:根据id查询商铺缓存的代码

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

 2、业务层

@Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result queryById(Long id) {
        // 从Redis 中查询商铺缓存
        String shopKey = RedisConstants.CACHE_SHOP_KEY + id;
        String shopJson = stringRedisTemplate.opsForValue().get(shopKey + id);
        // 判断是否存在
        if (!StringUtils.isEmpty(shopJson)) {
            // 存在则返回shop对象信息
            Shop shop = JSONObject.parseObject(shopJson, Shop.class);
            return Result.ok(shop);
        }
        // 不存在则查询数据库
        Shop shop = getById(id);
        if (shop == null) {
            return Result.fail("商品不存在");
        }
        // 存在则放入redis里
        stringRedisTemplate.opsForValue().set(shopKey + id, JSONObject.toJSONString(shop));
        return Result.ok(shop);
    }

2、查询分类的流程,是一个list,字符串的话,就用JSONArray

@Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryTypeList() {
        String key = "cache:shop:list";
        String listJson = stringRedisTemplate.opsForValue().get(key);
        log.info("listJson={}", listJson);
        if (!StringUtils.isEmpty(listJson)) {
            System.out.println("111111");
            JSONArray objects = JSONArray.parseArray(listJson);
            return Result.ok(objects);
        }
        List<ShopType> sort = query().orderByAsc("sort").list();
        stringRedisTemplate.opsForValue().set(key, JSONArray.toJSONString(sort));
        return Result.ok(sort);
    }

二、缓存更新策略

解决数据一致性问题

 主动更新

 针对上述3 先删除缓存,在操作数据库的问题缓存和数据库结果不一致,产生线程安全问题

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

  • 线程1查询缓存,缓存(恰好)失效了 未命中,查数据库的值是10。。(恰好查完要写缓存的同时,(在写得微秒范围内)线程二进来了,线程二去更新数据库,然后删缓存,在这个微秒的时间内,线程二执行完的可能性不高,因为缓存的速度,要高于磁盘的速度,即:要同时满足上面三个恰好
  • 线程2更新数据库20,删除缓存。
  • 线程1开始写缓存,写进去的就是旧数据10了,

方案二,如果恰巧出现了,那么我们以后给缓存加个超时时间,TTL 就好了

总结:写操作,即Update的时候

案例 

 1、给redis添加过期时间

stringRedisTemplate.opsForValue().set(shopKey + id, JSONObject.toJSONString(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);

2、修改操作

/**
     * 更新商铺信息
     * @param shop 商铺数据
     * @return 无
     */
    @PutMapping
    public Result updateShop(@RequestBody Shop shop) {
        // 写入数据库
        return shopService.update(shop);
    }

业务层:这里要开启事务,保证要么都执行,报错都回滚

@Override
    @Transactional /*开启事务保证磁盘操作和缓存操作的原子性*/
    public Result update(Shop shop) {
        Long id = shop.getId();
        if (id == null) {
            return Result.fail("店铺Id不能为空");
        }
        // 更新数据库操作
        updateById(shop);

        // 删除redis
        stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + id);
        return Result.ok();
    }

利用postMan手动触发接口,修改数据:put请求,然后可以去页面操作了,页面刷新回立即更改的

localhost:8081/shop


{
  "id": 1,
  "name": "118茶餐厅",
  "typeId": 1,
  "images": "https://qcloud.dpfile.com/pc/jiclIsCKmOI2arxKN1Uf0Hx3PucIJH8q0QSz-Z8llzcN56-_QiKuOvyio1OOxsRtFoXqu0G3iT2T27qat3WhLVEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vfCF2ubeXzk49OsGrXt_KYDCngOyCwZK-s3fqawWswzk.jpg,https://qcloud.dpfile.com/pc/IOf6VX3qaBgFXFVgp75w-KKJmWZjFc8GXDU8g9bQC6YGCpAmG00QbfT4vCCBj7njuzFvxlbkWx5uwqY2qcjixFEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vmIU_8ZGOT1OjpJmLxG6urQ.jpg",
  "area": "大关",
  "address": "金华路锦昌文华苑29号",
  "x": 120.149192,
  "y": 30.316078,
  "avgPrice": 80,
  "sold": 4215,
  "comments": 3035,
  "score": 37,
  "openH
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值