分布式缓存redis

1.分布式缓存概述

1.1.什么是分布式缓存

就是用户查询数据的时候,我们将数据从数据库中同步一份到内存中,客户端直接从内存中查询数据,减少了和数据库的交互次数,提高查询性能(内存读写很快),减轻数据库的压力,用户的体验感也会好
在这里插入图片描述

1.2.那些数据适合缓存
  • 经常查询的热点数据(热点数据,就是访问查询多的数据)

  • 不经常变的数据(数据变化会导致缓存中的数据跟着变,如果比较频繁,性能开销比较大)

1.3.缓存执行流程

  1. 每次查询,先看缓存是否有数据 , 如果有:直接返回

  2. 如果缓存没有数据,去数据库查询数据

  3. 把数据同步一份到缓存

  4. 返回数据
    【注意】数据库数据被修改,缓存要清空,或者重置
    在这里插入图片描述

1.3.为什么要分布式缓存
  • 在集群环境中,每个应用都有一个本地缓存,当缓存发生修改会造成缓存不同步问题

  • 本地缓存本身要占用应用的内存空间
    在这里插入图片描述

1.4.分布式缓存方案

使用Redis作为共享缓存 ,解决缓存不同步问题,Redis是独立的服务,缓存不用占用应用本身的内存空间
在这里插入图片描述

2.分布式缓存实战

比较流行的分布式缓存方案有:redis,mongdb等。我们选择Redis

2.1.集成Redis

SpringBoot提供了整合Redis的方案,我们使用spring-boot-starter-data-redis包就可以很方便的操作Redis了

1.导入依赖
<!--整合Redis , 底层可以用jedis-->
<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>

2.配置Redis

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123456
    jedis:
      pool:
        max-wait: 2000ms
        min-idle: 2
        max-idle: 8

3.Redis序列化配置
我们通常以JSON格式将数据存储到Redis中,这种格式是所有编程语言通用的,所以我们可以把Redis的序列化方式配置为JSON ,这样的话我们就可以不用自己去转JSON了

//缓存的配置
@Configuration
public class RedisConfig {

    @Resource
    private RedisConnectionFactory factory;


    //使用JSON进行序列化
    @Bean
    public RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        //JSON格式序列化
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
         //key的序列化
        redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer);
        //value的序列化
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        //hash结构key的虚拟化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //hash结构value的虚拟化
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

2.2.Redis测试

@Autowired
private RedisTemplate<Object, Object> redisTemplate;
...省略...
redisTemplate.opsForValue().set("key", "value");

项目测试:

package com.hy.ymcc.service.impl;

import com.hy.ymcc.domain.CourseType;
import com.hy.ymcc.mapper.CourseTypeMapper;
import com.hy.ymcc.service.ICourseTypeService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.hy.ymcc.vo.CourseCategoryVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author whale
 * @since 2025-10-23
 */
@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {
    @Autowired
    private CourseTypeMapper courseTypeMapper;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Override
    public List<CourseCategoryVO> getCourseTypeTree() {
        String key = "courseTypeTree";
        //先看缓存中有没有
        Object o = redisTemplate.opsForValue().get(key);
        if(o!=null){
            //有直接返回
            return (List<CourseCategoryVO>)o;
        }

        // 1. 查所有分类
        List<CourseType> allCategories = courseTypeMapper.selectAll();

        // 2. 按“父ID(pid)”分组,方便快速找子节点
        Map<Long, List<CourseType>> pidMap = allCategories.stream()
                .collect(Collectors.groupingBy(CourseType::getPid));

        // 3. 找所有“一级分类”(pid=0的节点),并递归找子节点
        List<CourseCategoryVO> rootNodes = new ArrayList<>();
        for (CourseType category : allCategories) {
            if (category.getPid() == 0) { // 一级分类的pid是0
                CourseCategoryVO vo = convertToVO(category);
                rootNodes.add(vo);
                findChildren(vo, pidMap); // 递归找子节点
            }
        }
        //缓存中没有 从数据中拿到的数据 添加到缓存里
        redisTemplate.opsForValue().set(key,rootNodes,5, TimeUnit.MINUTES);
        return rootNodes;
    }

    // 递归找子节点
    private void findChildren(CourseCategoryVO parentVO, Map<Long, List<CourseType>> pidMap) {
        List<CourseType> children = pidMap.get(parentVO.getId()); // 找“父ID等于当前节点ID”的子节点
        if (children != null && !children.isEmpty()) {
            for (CourseType child : children) {
                CourseCategoryVO childVO = convertToVO(child);
                parentVO.getChildren().add(childVO); // 把子节点加入当前节点的children列表
                findChildren(childVO, pidMap); // 继续找孙子节点
            }
        }
    }

    // 把数据库实体转成前端VO
    private CourseCategoryVO convertToVO(CourseType category) {
        CourseCategoryVO vo = new CourseCategoryVO();
        vo.setId(category.getId());
        vo.setName(category.getName());
        return vo;
    }
}

在这里插入图片描述

Logo

更多推荐