一.概述

注意:对于需要进行缓存的数据,必须要在它的类内定义序列版本号⭐。因为缓存是对数据的序列化和反序列化,不设置会导致类变更而无法反序列化

1.介绍

 对短期访问量大且结果相同的数据请求而言,可以将其进行缓存,进而减轻服务器硬盘IO的压力。数据的缓存常常使用的是Redis数据库,即将数据由对硬盘的IO读取转为对内存的IO读取,提高访问速率,也避免了无意义的重复业务

2.实现思路

将硬盘读取的IO操作,转到内存中,提高了效率

通过Redis来缓存菜品数据,减少数据库查询操作

image-20221208180818572

3.方案

  • 1.直接通过Redis客户端在特定的业务下对数据进行缓存、清理缓存操作
  • 2.使用SpringCache,采用注解的形式进行数据的缓存、清理缓存操作

二.Redis客户端

1.缓存

(1)步骤

  • 根据约定构建key
  • 查询Redis数据库中是否存在菜品数据
    • 存在:直接返回opsForValue().get(key)的结果
    • 不存在:先进行查询,再使用opsForValue().set(key,value)缓存到Redis数据库中

(2)示例

@GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result> list(Long categoryId) {

        //构造redis中的key,规则:dish_分类id
        String key = "dish_" + categoryId;

        //查询redis中是否存在菜品数据
        List list = (List) redisTemplate.opsForValue().get(key);
        if(list != null && list.size() > 0){
            //如果存在,直接返回,无须查询数据库
            return Result.success(list);
        }
		
        //如果不存在,查询数据库,将查询到的数据放入redis中
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品
        list = dishService.listWithFlavor(dish);//将查询数据库的结果存入Redis
        
        redisTemplate.opsForValue().set(key, list);

        return Result.success(list);
    }

2.清理缓存

(1)简述

**清理原因:**为了保持数据库和Redis中数据的一致性,我们需要在数据库数据更新的时候,对Redis中旧有的数据进行清理,让其重新进行缓存,从而保证数据的一致性

清理情况: 对数据库进行写操作的方法都要加上Redis清理方法,然后根据情况决定是要精细的清除其中一个还是将全部进行清理

(2)步骤

表达式就是Redis操作指令中keys的那个表达式,可以使用通配符

  • 先执行redisTemplate.keys()根据传入的表达式查询出要删除的key的集合
  • 再执行redisTemplate.delete()删除上面获取到的key集合

示例方法:

  private void ClearCache(String pattern) {
        //调用RedisTemplate查询传入的pattern对应的key,得到key的集合
        Set keys = redisTemplate.keys(pattern);//pattern可以是一个也可以是多个,效果一样的
        if (keys != null) {
            redisTemplate.delete(keys);
        }
    }

(3)示例

	/**
     * 修改菜品
     *
     * @param dishDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改菜品")
    public Result update(@RequestBody DishDTO dishDTO) {
        log.info("修改菜品:{}", dishDTO);
        dishService.updateWithFlavor(dishDTO);

        //将所有的菜品缓存数据清理掉,所有以dish_开头的key
        cleanCache("dish_*");

        return Result.success();
    }

三.Spring Cache

同一个业务中cacheNames请保持一致

1.概述

**简述:**Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

**缓存实现的切换:**Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现

  • Spring会根据Pom中导入的客户端而自动采用相应的缓存实现,不需要额外配置
    • EHCache
    • Caffeine
    • Redis(常用)

SPEL语法:

这个主要用于下面使用Spring Cache注解时设置Key的值

  • 类内元素:#类名.成员

    获取参数列表中的id的值

    @Cacheable(cacheNames = "userCache",key="#id")
    public User getById(Long id){}
    
  • 单个元素:#元素名

    访问参数列表中user对象内的id成员的值

        @CachePut(value = "userCache", key = "#user.id")
        public User save(@RequestBody User user){}
    

起步依赖:


	org.springframework.boot
	spring-boot-starter-cache  		            		       	 2.7.3 

2.注解

注解 说明
@EnableCaching 开启缓存注解功能,通常加在启动类上 (开启缓存支持)
@Cacheable 在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法返回值放到缓存中 (又放又取)
@CachePut 将方法的返回值放到缓存中 (只放不取)
@CacheEvict 将一条或多条数据从缓存中删除 (清理缓存)

(1)EnableCaching

该注解是附加在启动类上用于开启缓存注解功能的

@Slf4j
@SpringBootApplication
@EnableCaching//开启缓存注解功能
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}

(2)Cacheable

作用: 在方法执行前,spring先查看缓存中是否有数据,

  • 如果有数据,则直接返回缓存数据;

  • 若没有数据,调用方法并将方法返回值放到缓存中

参数:

  • cacheNames:缓存的名称,每个缓存下可以有多个key

    • 获取、删除的时候需要保证缓存名称都一致,否则会出问题
  • key: 缓存的key

    使用Spring的表达式语言SPEL语法指定(详见下面附录)

格式:

@Cacheable(cacheNames = "缓存名称",key="缓存的key")

示例:

	@GetMapping
    @Cacheable(cacheNames = "userCache",key="#id")
    public User getById(Long id){
        User user = userMapper.getById(id);//根据ID获取缓存,当缓存中没有时,才会去调用Mapper查询数据
        return user;
    }

(3)CachePut

作用:方法返回值,放入缓存

参数:

  • value:缓存的名称,每个缓存下可以有多个key

    • 获取、删除的时候需要保证缓存名称都一致,否则会出问题
  • key: 缓存的key

    使用Spring的表达式语言SPEL语法指定(详见下面附录)

格式:

 @CachePut(value = "缓存名称", key = "缓存的key")

示例:

	@PostMapping
    @CachePut(value = "userCache", key = "#user.id")//key的生成:userCache::1
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

(4)CacheEvict

**作用:**清理指定的缓存

参数:

  • cacheNames:缓存的名称,每个缓存下可以有多个key

    • 获取、删除的时候需要保证缓存名称都一致,否则会出问题
  • key: 缓存的key

    使用Spring的表达式语言SPEL语法指定

  • allEntries:该属性可以指定删除Redis中的所有缓存

    • 和key不共存,二者只能出现一个

格式:

1.删除某个key对应的缓存数据

@CacheEvict(cacheNames = "缓存名称",key = "缓存的key")

2.删除指定cacheNames下的所有缓存数据

@CacheEvict(cacheNames = "缓存名称",allEntries = true)

示例:

	@DeleteMapping
    @CacheEvict(cacheNames = "userCache",key = "#id")//删除某个key对应的缓存数据
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }

	@DeleteMapping("/delAll")
    @CacheEvict(cacheNames = "userCache",allEntries = true)//删除userCache下所有的缓存数据
    public void deleteAll(){
        userMapper.deleteAll();
    }
最后修改:2024 年 03 月 18 日
如果觉得我的文章对你有用,请随意赞赏