9.缓存优化

缓存优化

1、环境搭建

1.1、导入maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

1.2、配置redis

我的redis直接装在了windows上,所以host为本地地址。安装方法看此博客:https://www.redis.com.cn/redis-installation.html

image-20220626131713166

1.3、redis配置类

在config目录下创建RedisConfig类,

这里不推荐把value也设置成StringRedisSerializer,如果设置成StringRedisSerializer,后面向redis中存入集合时会发生转换异常。

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //默认的Key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer()); // key序列化
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }

}

1.4、推送

提交并推送到github,签名:redis环境配置。注意分支为 v1.0

2、缓存短信验证码

2.1、实现思路

  1. 在服务端UserController中注入RedisTemplate对象,用于操作Redis
  2. 在服务端UserController的sendMsg方法中,将随机生成的验证码缓存到Redis中,并设置有效期为5分钟
  3. 在服务端UserController的login方法中,从Redis中获取缓存的验证码,如果登录成功则删除Redis中的验证码

2.2、修改UserController

2.2.1、修改sendMsg方法

image-20220626133300418

2.2.2、修改login方法

image-20220626133511439

2.3、测试

安装一个redis可视化界面进行测试,我使用的是Another Redis Desktop Manager

2.4、推送代码

提交并推送代码,签名:缓存短信验证码。

3、缓存菜品

3.1、实现思路

  1. 改造DishController的list方法,先从Redis中获取菜品数据,如果有则直接返回,无需查询数据库;如果没有则查询数据库,并将查询到的菜品数据放入Redis。
  2. 改造DishController的save和update方法,加入清理缓存的逻辑

3.2、修改DishController

3.2.1、修改list方法
/**
 * 根据条件查询对应的菜品数据
 *
 * @param dish
 * @return
 */
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish) {
    List<DishDto> dishDtoList = null;

    String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();

    // 先从redis获取数据
    dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);

    if (dishDtoList != null) {
        // 如果redis中有数据则直接返回
        return R.success(dishDtoList);
    }

    // 构造查询条件
    LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
    // 查询状态为1的菜品
    queryWrapper.eq(Dish::getStatus, 1);

    // 添加排序条件
    queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

    List<Dish> list = dishService.list(queryWrapper);

    dishDtoList = list.stream().map(item -> {
        DishDto dishDto = new DishDto();
        // 拷贝属性
        BeanUtils.copyProperties(item, dishDto);

        // 设置DishDto分类名称属性
        Long categoryId = item.getCategoryId();
        Category category = categoryService.getById(categoryId);
        if (category != null) {
            String categoryName = category.getName();
            dishDto.setCategoryName(categoryName);
        }

        // 设置菜品口味
        Long dishId = item.getId();
        LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId, dishId);
        // SQL: select * from dish_flavor where dish_id = ?
        List<DishFlavor> dishFlavorList = dishFlavorService.list(dishFlavorLambdaQueryWrapper);
        dishDto.setFlavors(dishFlavorList);

        return dishDto;
    }).collect(Collectors.toList());

    // 将数据存入redis
    redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);

    return R.success(dishDtoList);
}
3.2.2、修改update方法
/**
 * 修改菜品
 * @param dishDto
 * @return
 */
@PutMapping
public R<String> update(@RequestBody DishDto dishDto) {
    log.info(dishDto.toString());

    dishService.updateWithFlavor(dishDto);

    // 清理所有菜品的缓存数据
    // Set keys = redisTemplate.keys("dish_*");
    // redisTemplate.delete(keys);
    
    // 清理某个分类下面的菜品缓存数据
    String key = "dish_" + dishDto.getCategoryId() + "_1";
    redisTemplate.delete(key);

    return R.success("修改菜品成功");
}
3.2.3、修改save方法
/**
 * 新增菜品
 * @param dishDto
 * @return
 */
@PostMapping
public R<String> save(@RequestBody DishDto dishDto) {
    log.info(dishDto.toString());
    dishService.saveWithFlavor(dishDto);

    // 清理所有菜品的缓存数据
    // Set keys = redisTemplate.keys("dish_*");
    // redisTemplate.delete(keys);

    // 清理某个分类下面的菜品缓存数据
    String key = "dish_" + dishDto.getCategoryId() + "_1";
    redisTemplate.delete(key);
    
    return R.success("新增菜品成功");
}
3.2.4、修改delete方法
/**
 * 逻辑删除
 * @param ids
 * @return
 */
@DeleteMapping
@Transactional
public R<String> delete(Long[] ids) {
    log.info("批量删除的id:{}", Arrays.toString(ids));
    // 先逻辑删除菜品对应的口味信息
    dishFlavorService.removeByDishIds(Arrays.asList(ids));
    // 在逻辑删除菜品
    dishService.removeByIds(Arrays.asList(ids));

    // 清理所有菜品的缓存数据
    // Set keys = redisTemplate.keys("dish_*");
    // redisTemplate.delete(keys);

    // 根据dishId集合查询出categoryId集合
    List<Dish> dishes = dishService.listByIds(Arrays.asList(ids)); // 查询所有id在ids里的dish记录
    Set<Long> categoryIds = dishes.stream().map(Dish::getCategoryId).collect(Collectors.toSet());// 取出字段category_id集合,set集合防止重复

    // 清除所有id在categoryIds中的缓存
    categoryIds.forEach(item -> {
        String key = "dish_" + item + "_1";
        redisTemplate.delete(key);
    });

    return R.success("删除菜品成功");
}
3.2.5、测试缓存效果
3.2.6、推送代码

提交并推送代码,签名:缓存菜品。分支:v1.0

4、合并代码

将 v1.0 分支的代码合并到主分支上

  1. 切换回主分支
  2. 再点击 v1.0 分支的合并按钮
  3. 合并完后切换回 v1.0 分支继续开发

5、SpringCache缓存套餐数据

5.1、实现思路

  1. 导入Spring Cache和Redis相关maven坐标
  2. 在application.yml中配置缓存数据的过期时间
  3. 在启动类上加入@EnableCaching注解,开启缓存注解功能
  4. 在SetmealController的list方法上加入@Cacheable注解
  5. 在SetmealController的save和delete方法上加入CacheEvict注解

5.2、导入maven

之前已经导入了redis的相关依赖,现在只需要导入spring cache:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

5.3、开启缓存功能

在启动类上标注@EnableCaching注解

5.4、返回类型R实现序列化

public class R<T> implements Serializable

5.5、缓存套餐信息

1、修改SetmealController里的list方法

/**
 * 根据分类id和状态查询套餐
 * @param setmeal
 * @return
 */
@GetMapping("/list")
@Cacheable(value = "setmealCache", key = "#setmeal.categoryId + '_' + #setmeal.status")
public R<List<Setmeal>> list(Setmeal setmeal) {
    LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
    queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
    queryWrapper.orderByDesc(Setmeal::getUpdateTime);

    List<Setmeal> list = setmealService.list(queryWrapper);

    return R.success(list);
}

2、给SetmealController下的deletesaveupdate方法都标上以下注解

@CacheEvict(value = "setmealCache", allEntries = true)

5.6、测试缓存

手机界面登陆后点击套餐查询,查看效果

5.7、推送代码&合并

提交并推送代码,签名:spring cache缓存套餐数据。分支:v1.0

合并步骤:

  1. 先切换到master分支
  2. 点击v1.0分支的合并按钮进行合并
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值