前言

这篇文章主要介绍 Redis 在项目中的使用,实现常见的一些功能。
需要 Redis 基础知识,可以参考之前的文章:Redis 基础

Session 共享分布式登录

场景

项目中单点登录,将用户信息存放到 Session 中,
存在这样的问题:为什么用户在服务器 A 登录,向服务器 B 发请求时,服务器不认识该用户?
原因:用户信息在 A 的内存中,B 和 A 的内存是独立的两个空间。

解决:共享存储,实现分布式登录

Redis 实现

代码很简单,学习思想~

  1. 引入 redis,为了操作 redis

    1
    2
    3
    4
    5
    6
    <!-- 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>
    <version>2.6.4</version>
    </dependency>
  2. 引入 spring-session 和 redis 的整合,为了自动将 session 存储到 redis

    1
    2
    3
    4
    5
    6
    <!-- 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.4</version>
    </dependency>
  3. 修改 spring-session 的存储配置

    1
    2
    3
    spring:
    session:
    store-type: redis
  4. 配置 redis

    1
    2
    3
    4
    5
    spring:
    redis:
    host: host
    port: port
    database: 0~15

数据缓存

场景

当我们的数据量比较大时,直接读取数据库中的数据会非常慢(MySQL 存储到磁盘)。
解决方法:把数据读取出来然后保存到更快的介质,例如内存,实现更快地读写。
Redis 刚好是一个高性能的 K/V 内存存储系统~

Redis 实现

整合

  1. 引入 redis

    1
    2
    3
    4
    5
    6
    <!-- 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>
    <version>2.6.4</version>
    </dependency>
  2. 配置 redis

    1
    2
    3
    4
    5
    spring:
    redis:
    host: host
    port: port
    database: 0~15
  3. 配置 RedisTemplate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /**
    * @author ShameYang
    * @date 2024/5/22 16:43
    * @description RedisTemplate 配置
    */
    @Configuration
    public class RedisTemplateConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    //创建 RedisTemplate 对象
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    //设置连接工厂
    redisTemplate.setConnectionFactory(connectionFactory);
    //设置 Key 的序列化
    redisTemplate.setKeySerializer(RedisSerializer.string());

    //创建 Json 序列化工具
    GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
    //设置 Value 的序列化
    redisTemplate.setValueSerializer(jsonRedisSerializer);
    return redisTemplate;
    }
    }

数据缓存

  1. 设计缓存 key systemId:moduleId:func:options

  2. 修改查询数据的方法:有缓存就读取,没有则读取数据库,写到缓存中(一定要设置过期时间!!!)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    String redisKey = String.format("friendhub:user:recommend:%s", loginUser.getId());
    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    // 有缓存,直接读取
    Page<User> userPage = (Page<User>) valueOperations.get(redisKey);
    if (userPage != null) {
    return;
    }
    // 没有缓存,查数据库
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    userPage = userService.page(new Page<>(pageNum, pageSize), queryWrapper);
    // 写缓存,10s过期
    try {
    valueOperations.set(redisKey, userPage, 10000, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
    log.error("redis set key error", e);
    }

定时任务/数据预热

我们只进行了数据缓存,但是存在一个问题:第一个访问的用户会读取数据库,加载慢,体验很差
数据预热,可以解决这个问题,让用户的访问始终很快。
需要根据具体的场景决定是否进行数据预热!!
定时任务参考文章:SpringBoot 实现定时任务-@Scheduled

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
@Component
@Slf4j
public class PreCacheJob {

@Resource
private UserService userService;

@Resource
private RedisTemplate<String, Object> redisTemplate;

// 重点用户
private List<Long> mainUserList = Arrays.asList(1L);

// 每天执行,预热推荐用户
@Scheduled(cron = "0 12 1 * * *") // 自己设置时间测试
public void doCacheRecommendUser() {
// 查数据库
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Page<User> userPage = userService.page(new Page<>(1,20), queryWrapper);
String redisKey = String.format("friendhub:user:recommend:%s", mainUserList);
ValueOperations valueOperations = redisTemplate.opsForValue();
// 写缓存, 30s过期
try {
valueOperations.set(redisKey,userPage, 30000, TimeUnit.MILLISECONDS);
} catch (Exception e){
log.error("redis set key error",e);
}
}
}