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

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

缓存的实现

分布式缓存

  • 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

引入依赖

        <!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>2.6.3</version>
        </dependency>

yml

spring:
  redis:
    host: localhost
    port: 6379
    database: 0

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"));

    }
}

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

用quickredis查看

image-20220913091004490

怎么回事

看看redisTempalte干了什么

image-20220913091310232

image-20220913091522867

redisTemplate序列化了

image-20220913091622567

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

我们加个泛型

@Resource
private RedisTemplate<String, Object> redisTemplate;

没什么用

我们用StringRedisTemplate

 @Resource
    private StringRedisTemplate stringRedisTemplate;


    @Test
    public void testRedis() {
        ValueOperations value = stringRedisTemplate.opsForValue();

但是其他类型的不行了

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<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        return redisTemplate;
    }
}

再改回用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<String, Object> valueOperations = redisTemplate.opsForValue();
        String redisKey = String.format("partner:user:recommed:userId",loginUser.getId());
        //如果有缓存。查缓存
        Page<User> page = (Page<User>) valueOperations.get(redisKey);
        if (page != null) {
            return ResultUtils.success(page);
        }
        //没缓存继续查数据库
        //不登录也推荐,但是不个性化,每个人一样
        //登录之后就个性化推荐
        QueryWrapper<User> 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);
        }
}

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

设置下过期时间

image-20220913104349624

测试一下

10s过期

删除下之前的key

重新发请求

10s之后就没了

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐