• SpringBoot使用redis解决分页查询大量数据慢的情况


    数据量大的时候,即使分页查询速度也会变慢

    用缓存:提前把数据取出来保存好(通常保存到读写更快的介质,比如内存),就可以更快地读写。

    缓存的实现

    分布式缓存

    • Redis(分布式缓存)
    • memcached(分布式)
    • Etcd(云原生架构的一个分布式存储,存储配置,扩容能力)

    java的进程缓存

    • ehcache(单机)

    • 本地缓存(Java 内存 Map)

    • Caffeine(Java 内存缓存,高性能)

    • Google Guava

    单机缓存

    image-20220912113214544

    数据不一致

    解决方法:主从复制

    分布式缓存

    image-20220912113353858

    Redis可以作为分布式缓存

    Redis

    NoSQL数据库

    key-value存储系统(区别于MySQL存储的键值对)

    Java里的实现方式

    • Spring Data Redis
    • Jedis
    • Redisson

    Spring Data Redis(推荐)

    通用的数据访问框架、提供了一组增删改查的接口

    操作mysql、redis

    引入依赖

            
            
                org.springframework.session
                spring-session-data-redis
                2.6.3
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    yml

    spring:
      redis:
        host: localhost
        port: 6379
        database: 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Redis的数据结构

    String 字符串类型:name:“aaa”

    List列表:names:[“aaa”,“aab”,“aaa”]

    Set集合: names:[“aa”,“ab”]

    Hash哈希:nameAge:{“aa”:1,“dd”:2}

    Zset集合:names:{aaa-9,bbb-12}适合做排行榜

    redis也可以做消息队列


    bloomfilter(布隆过滤器,主要从大量的数据中快速过滤值,比如邮件黑名单拦截)

    geo(计算地理位置)

    hyperloglog(pv / uv)

    pub / sub(发布订阅,类似消息队列)

    BitMap (1001010101010101010101010101)

    测试一下

    package com.bo.partner.service;
    
    import com.bo.partner.model.domain.User;
    import org.junit.Test;
    import org.junit.jupiter.api.Assertions;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.test.context.junit4.SpringRunner;
    
    /**
     * @author: bo
     * @date: 2022/9/12
     * @description:
     */
    @SpringBootTest
    public class RedisTest {
        @Autowired
        private RedisTemplate redisTemplate;
    
    
        @Test
        public void testRedis() {
            ValueOperations value = redisTemplate.opsForValue();
            value.set("aaaString", "aka");
            value.set("aaaint", 1);
            value.set("aaadouble", 2.0);
            User user = new User();
            user.setId(1L);
            user.setUsername("aaa");
            value.set("aauser",user);
            Object aaaString = value.get("aaaString");
            Assertions.assertTrue("aka".equals((String)aaaString));
            Object aaaint = value.get("aaaint");
            Assertions.assertTrue(1==((Integer)aaaint));
            Object aaadouble = value.get("aaadouble");
            Assertions.assertTrue(2.0==((Double)aaadouble));
            System.out.println(value.get("aauser"));
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    报错,空指针异常,解决方法:加个注解@RunWith(SpringRunner.class)

    用quickredis查看

    image-20220913091004490

    怎么回事

    看看redisTempalte干了什么

    image-20220913091310232

    image-20220913091522867

    redisTemplate序列化了

    image-20220913091622567

    if序列化器是空,用的java原生的序列化器

    我们加个泛型

    @Resource
    private RedisTemplate redisTemplate;
    
    • 1
    • 2

    没什么用

    我们用StringRedisTemplate

     @Resource
        private StringRedisTemplate stringRedisTemplate;
    
    
        @Test
        public void testRedis() {
            ValueOperations value = stringRedisTemplate.opsForValue();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    但是其他类型的不行了

    image-20220913092112269

    注释掉其他的

    成功

    image-20220913092205516

    但是没有其他的实现类

    写一个配置类吧

    package com.bo.partner.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.RedisSerializer;
    
    /**
     * @author: bo
     * @date: 2022/9/13
     * @description:
     */
    @Configuration
    public class RedisTemplateConfig {
        @Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
            RedisTemplate redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(connectionFactory);
            redisTemplate.setKeySerializer(RedisSerializer.string());
            return redisTemplate;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    再改回用redisTemplate

    image-20220913092704067

    运行成功

    redisTemplate默认用了Lettuce

    image-20220913165027956

    点进去

    image-20220913165016643

    Jedis

    独立于spring操作redis

    Lettuce

    高阶的操作redis的客户端

    异步、连接池

    连接池

    复用连接

    Redisson

    分布式操作redis的java客户端

    让你像在本地使用集合一样操作redis

    分布式数据网格

    使用场景

    1. 如果你用的是 Spring,并且没有过多的定制化要求,可以用 Spring Data Redis,最方便
    2. 如果你用的不是 Spring,并且追求简单,并且没有过高的性能要求,可以用 Jedis + Jedis Pool
    3. 如果你的项目不是 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
    4. 如果你的项目是分布式的,需要用到一些分布式的特性(比如分布式锁、分布式集合),推荐用 redisson

    设计缓存 key

    不同用户看到的数据不同

    systemId:moduleId:func:options(不要和别人冲突)光userid容易冲突

    partner:user:recommed:userId

    redis 内存不能无限增加,一定要设置过期时间!!!

     User loginUser = userService.getLoginUser(request);
            ValueOperations valueOperations = redisTemplate.opsForValue();
            String redisKey = String.format("partner:user:recommed:userId",loginUser.getId());
            //如果有缓存。查缓存
            Page page = (Page) valueOperations.get(redisKey);
            if (page != null) {
                return ResultUtils.success(page);
            }
            //没缓存继续查数据库
            //不登录也推荐,但是不个性化,每个人一样
            //登录之后就个性化推荐
            QueryWrapper queryWrapper = new QueryWrapper<>();
             page = userService.page(new Page<>(pageNum,pageSize), queryWrapper);
             //写缓存
            try {
                valueOperations.set(redisKey,page);
            } catch (Exception e) {
                log.error("redis set key error", e);
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    不能用户每天看到的一样推荐

    设置下过期时间

    image-20220913104349624

    测试一下

    10s过期

    删除下之前的key

    重新发请求

    10s之后就没了

  • 相关阅读:
    flex布局方法学习
    警方打击了大规模网络钓鱼提供商BulletProftLink
    ElasticSearch 使用 searchAfter() 进行遍历查询 查到的数据总数小于 totalHits
    Linux:linux getopt_long()函数(命令行解析)(getopt、getopt_long_only)(短选项 -,长选项 --)
    Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务
    HTTP 响应行 错误类型响应码
    [cocos creator] Label设置为RESIZE_HEIGHT,获取height
    请求本地的 JSON 文件作为 mock 数据
    PTrade和QMT对比那个更好用?
    为element-ui对话框组件(el-dialog)添加弹窗拖拽支持
  • 原文地址:https://blog.csdn.net/qq_46110710/article/details/126837377