谷粒商城—缓存—缓存(151~156)

一.缓存使用:

            1)缓存 介绍: 
                    a:为了系统性能 的提升,会将 部分数据放入缓存中,可以加速访问,而 DB 只承担数据落盘工作。
                    b:哪些数据 适合放入缓存?

                                -1.及时性 / 数据一致性 要求不高的。
                                -2.访问量大且频率更新不高的数据(读多,写少)。

                    c:读模式 缓存使用 流程:( 图示 / 代码)
  



            2)整合 Redis: 
                    a:添加 POM 文件:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

                    b:配置文件:
                                  a:Redis 配置类是 :RedisAutoConfiguration.class
                                  b:Redis 配置文件 可配置的 选项:RedisProperties.class
                                  c:写配置文件:application.yml:

spring:
  redis:
    host: 114.215.173.88
    port: 6379

                                  d:编写 测试类,进行 Redis 测试:

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void contextLoads2() {
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();

        operations.set("hello", "workd : " + UUID.randomUUID().toString());
        String hello = operations.get("hello");
        System.out.println(hello);
    }


            3)优化 三级查询 业务,加入缓存功能: 
​​​​​​​                    a:Service 代码 优化:

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryVo> listWithTree() {
        //1.加入缓存逻辑
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        //2.从缓存中获取对象
        String listWithTree = operations.get("listWithTree");

        if (StringUtils.isEmpty(listWithTree)) {
            log.info("查询 数据库了。");
            //3.缓存中 没有,从数据库 查询出来
            List<CategoryVo> categoryVos = getCategoryVos();
            //4.把 查询 出来的 数据,放入缓存,方便下次查询。
            //   [序列化 与 反序列化]
            operations.set("listWithTree", JSON.toJSONString(categoryVos));
            return categoryVos;
        }
        //[序列化 与 反序列化]
//        return JSON.parseObject(listWithTree, new TypeReference<List<CategoryVo>>() { }
        log.info("直接 返回 了");
        List<CategoryVo> categoryVoList = JSON.parseArray(listWithTree, CategoryVo.class);
        return categoryVoList;
    }

​​​​​​​                    b:fastJson (List 和 JSON 互相转换):见 a



            4)加缓存后,压力测试(内存泄漏问题): 
​​​​​​​                    a:outofdirectmemoryerror 形成原因:
                                  a:SpringBoot 2.0 以后,默认使用 lettuce,作为 操作 redis 的客户端。它使用 netty 进行网络通信。
                                  b:lettuce 的 bug ,导致 netty 堆外 内存溢出。
​​​​​​​                    b:解决方法:
                                  a:升级 lettuce 客户端。
                                  b:将 lettuce 去除,换为 Jedis 连接 Redis。

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>


            4)高并发下,缓存失效的问题:(https://blog.csdn.net/qq_43056248/article/details/118355838
​​​​​​​                    a:缓存 穿透:
                                 -1.概念:指 查询一个 一定不存在的 数据,由于缓存不命中,则会去数据库中查询,但是数据库也无此记录,没有将这次查询到的 null 写入缓存(写入一个标志),导致 这个不存在的数据,每次请求,都要到 数据库 中查询,失去了缓存的意义。
                                 -2.风险:利用不存在的 数据进行攻击,数据库 顺势压力增大。
                                 -3.解决:null 结果,也加入缓存中,并且加入 短暂过期时间。

​​​​​​​                    b:缓存击穿:(缓存雪崩的其中一个)
                                 -1.概念:对于 一些设置了 过期时间的 key,如果这些 key,可能会在 某些时间点,被超高并发访问,是一种 非常热点的数据。如果 这个 key ,在大量请求 进来的同时前 正好失效,那么这个 key 的数据查询,都会落到 数据库 上,我们称为 缓存击穿。
                                 -2.解决:加锁,大量 并发,只让一个人查询,其他人等待,查询到数据以后,数据存入缓存。释放锁,其他人获取到锁,先查缓存,就会有数据,不用去 查询 数据库。

​​​​​​​                    c:缓存雪崩:
                                 -1.概念:指 我们在设置 缓存时 的 key,采用了相同的过期时间,导致大量缓存,在某一时刻同时失效,请求全部转发到 数据库,数据库 瞬时压力过重,导致缓存雪崩。
                                 -2.解决:在设置 缓存时,在原有的失效时间基础上,增加一个随机值,比如 1~5 分钟随机,这样,每一个缓存过期时间的重复率就会降低,很难引发集体失效的事件。


            4)三级查询 业务,优化缓存:
​​​​​​​                    a:空结果缓存,解决 缓存穿透 问题。
​​​​​​​                    b:key 设置随机,过期时间,解决缓存雪崩问题。
​​​​​​​                    c:加锁,解决缓存击穿问题。(本地锁)

    private List<CategoryVo> getCategoryVos() {

        //加锁
        synchronized (this) {

            //再次判断缓存中是否有数据。有直接返回
            String listWithTree = stringRedisTemplate.opsForValue().get("listWithTree");
            if (!StringUtils.isEmpty(listWithTree)) {
                List<CategoryVo> categoryVoList = JSON.parseArray(listWithTree, CategoryVo.class);
                return categoryVoList;
            }

            //1.查出所有分类
            ......

            //2.放缓存中。
            ......

            //返回组装好的 三级分类树
            return collect;
        }
    }



        4)本地锁在 分布式情况下 的问题
​​​​​​​                    a:复制 gulimail-product 项目,启动多个,并修改端口( --server.port=10002 )
​​​​​​​                    b:多个服务,每个服务都会查询 1 次 数据库,本地锁 锁不住。




 

三.Spring Cache 缓存 框架

        1)Spring Cache 简介:

                 1)注解介绍:
                                  a:@Cacheable:触发​​缓存填充。
                                  b:@CacheEvict:触发​​缓存逐出。
                                  c:@CachePut: 在不干扰方法执行的情况下更新缓存。
                                  d:@Caching:  重新组合要在一个方法上应用的多个缓存操作。
                                  e:@CacheConfig:在类级别共享一些与缓存相关的常见设置。
                 2):
 

        2)整合 Spring Cache,简化缓存开发 :

                 1)添加 redis,cache 依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

                 1)写 配置文件:
                                  a:@

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值