缓存问题:缓存穿透

 文章目录


前言

        缓存穿透是指,查询数据库中的一个一定不存在的数据,查询流程是先对redis进行查询,缓存未命中,在对数据库进行查询,假如存在10w个不存在的数据查询请求,这十万个请求将全部打到数据库上面。

一、解决方案一

        对不存在的数据,我们也进行缓存,这个数据是一个固定的值,比如x,每个查询到这个固定的值x,直接返回从而减小数据库的压力。

参考代码

    public List<CategoryVo> findCatgorysTree() {

        String catgorysJsonStr = redisTemplate.opsForValue().get(GmallConstant.REDIS_CACHE_CATEGORY_KEY);
        //判断缓存之中是否有数据
        if (!StringUtils.isEmpty(catgorysJsonStr)) {
            //存在
            //判断这个值是否是x,
            if ("x".equals(catgorysJsonStr)) {
                //是x,
                log.info("数据库中不存在的值,redis返回null......");
                //返回null
                return null;
            } else {
                //不是x,是说明是真是存在的数据
                //返回
                return JSON.parseArray(catgorysJsonStr, CategoryVo.class);
            }
        } else {//缓存之中没有数据
            //查询数据库
            List<CategoryVo> categoryVoList = baseCategory1Mapper.findCatgorysTree();
            //是否查出这个数据
            if (categoryVoList != null && categoryVoList.size() != 0) {
                log.info("数据库中存在这个值.........");
                //数据库存在这个值
                String toJSONString = JSON.toJSONString(categoryVoList);
                //返回redis中在返回
                redisTemplate.opsForValue().set(GmallConstant.REDIS_CACHE_CATEGORY_KEY, toJSONString);
                return categoryVoList;
            } else {
                log.info("数据中不存在这个值.........");
                //数据库中不存在这个值
                redisTemplate.opsForValue().set(GmallConstant.REDIS_CACHE_CATEGORY_KEY, "x");
                return categoryVoList;
            }
        }
    }

        存在的弊端:无法解决随机值穿透的问题,其他值还是会请求数据库,并且每一次请求都会在redis中进行存储一个值  x,对于redis的内存消耗比较严重。

二、解决方案二(方案一优化)

        缓存预热:服务启动时就将数据从数据库缓存到redis中,在数据查询的时候以缓存中的数据为准,缓存中如果存在数据,直接返回,不存在返回null。

        存在的弊端:消耗redis中的内存,缓存一致性问题。

三、解决方案三(使用过滤器的思想)

开辟两个内存空间,存储不同的内容. 

三、解决方案四(对解决方案三改进,减少skuId的内存消耗):布隆过滤器

  1. 布隆过滤器作用:判断一个数据是否存在
  2. 布隆过滤器的组成:二级制数组 +  hash函数
  3. 布隆过滤器存储数据的过程:对要存储的数据进行hash计算,将对应结算结果作为数组的索引,并将对应索引上的值更改为1(默认为0)
  4. 布隆过滤器如何判断数据是否存在:对需要判断的数据进行hash计算,判断对应索引上的值是否全部为1,如果为1,则可能存在,如果存在不为1的,则一定不存在
  5. 布隆过滤器不支持删除。

 入门案例

package com.atguigu.gmall;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterTest {
    public static void main(String[] args) {
        //初始化一个布隆过滤器
        /**
         * Funnel<? super T> funnel, 限定布隆过滤器中存储的元素类型
         * int expectedInsertions,   期望布隆过滤器中存储的元素个数
         * double fpp,              误判率,越低,数组越大
         */
        BloomFilter<Long> longBloomFilter = BloomFilter.create(Funnels.longFunnel(), 100000, 0.0000001);
        //向布隆过滤器中添加数据
        longBloomFilter.put(45l);
        longBloomFilter.put(50l);
        longBloomFilter.put(53l);
        //判断数据在布隆过滤器中是否存在
        System.out.println(longBloomFilter.mightContain(45l));
        System.out.println(longBloomFilter.mightContain(50l));
        System.out.println(longBloomFilter.mightContain(100l));
    }
}

在解决方案二中服务启动时就将数据从数据库缓存到redis中,如何去做?

        spring的生命周期:

  1. 通过实现InitializingBean接口继承afterPropertiesSet()方法
  2. 自定义init()方法,加上@PostConstruct注解.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值