我们优先去读取缓存数据,如果有就直接使用,如果没有再去查询数据库,查出来之后再放到缓存里去。
微信小程序根据分类来展示菜品,所以每一个分类下边的菜品对应的就是一份缓存数据,这样的话当我们使用这个数据的时候,就可以一次性的把这个分类下面的缓存数据给它加载出来。Redis保存数据是key-value结构,我们可以使用分类的id来作为我们缓存的key,而value则是分类下面这些具体的菜品数据,这些菜品数据可以使用String字符串来进行保存。Redis当中的数据类型跟Java当中的数据类型并不是完全对应的,也就是说Java当中任何一个对象,都可以给它转成Redis当中的String字符串来进行存储。从Java对象这个角度来考虑,这些一个分类下面的具体菜品数据可以用List集合进行存储,然后把这个集合进行序列化,最终转成Redis的一个字符串来存储。
数据库中菜品数据有变更时清理缓存数据,如果不清理会造成我们这个数据的不一致,比如说在商家管理端把某一个菜品的价格改了,如果不清理对应的缓存,因为管理端改了菜品价格修改的是MySQL数据库里面数据,但是小程序展示出来的是读取缓存Redis里面的数据,Redis里面的数据没有改,所以小程序里面展示的还是原来的价格。
1.查询redis中是否存在菜品数据。放进去是什么类型的取出来就是什么类型的,放进去是List<DishVo>类型的所以取出来要强转成List<DishVo>类型的。
2.如果存在,直接返回,无须查询数据库。
3.如果不存在,查询数据库,将查询到的数据放入redis中。
数据缓存到了Redis里
使用Redis缓存数据要保证数据的一致性,这个数据的一致性主要是体现在我们MySQL数据库当中的数据跟Redis缓存当中的数据必须是一致的,也就是说当我们MySQL数据库当中的数据发生变更时,我们需要及时的把Redis缓存的数据清理掉,然后它重新去查MySQL数据库,这样的话就一致了。
新增菜品我们可以精确的去清理掉分类id对应的缓存数据。
菜品批量删除有可能会删除多个菜品,而多个菜品可能属于某一个分类下边,也可能是某些不同分类下边的菜品,也就是它可能会影响到多个key,影响到哪个key,需要查询MySQL数据库才会知道。这样太复杂,所以如果执行了菜品批量删除,我们就把所有的缓存数据清理掉,也就是dish_开头的数据都给它清理掉。删除的时候不能识别通配符,所以我们先把所有的key查询出来,然后再去删除。
修改菜品如果是修改了分类,那就影响到了两份缓存数据,也就是原先的分类会少一个,修改后的分类会多一个,如果修改的是菜品名称,价格这些属性则只会影响一份缓存数据。这样看来修改菜品有可能会影响一份缓存数据,有可能会影响两份缓存数据,修改操作并不是常规操作,一般很少去修改,所以我们这里简单的处理了,统一清理掉所有的缓存数据
菜品起售停售,需要根据菜品id把对应的数据查出来,菜品数据里面就有分类id,这样就可以动态的把key构造出来,这样就可以清理某一个key,也就是菜品起售停售对应的缓存数据,这样去实现还要额外去查询数据,所以这里我们统一清理所有的缓存数据。
package com.sky.controller.admin;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
/**
* 菜品管理
*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
@Autowired
private DishService dishService;
@Autowired
private RedisTemplate redisTemplate;
/**
* 新增菜品
* @param dishDTO
* @return
*/
@PostMapping
@ApiOperation("新增菜品")
public Result save(@RequestBody DishDTO dishDTO) {
log.info("新增菜品:{}", dishDTO);
dishService.saveWithFlavor(dishDTO);
//清理缓存数据
String key = "dish_" + dishDTO.getCategoryId();
cleanCache(key);
return Result.success();
}
/**
* 菜品分页查询
*
* @return
*/
@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
log.info("菜品分页查询:{}", dishPageQueryDTO);
PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
/**
* 菜品批量删除
* @param ids
* @return
*/
@DeleteMapping
@ApiOperation("菜品批量删除")
public Result delete (@RequestParam List<Long> ids){
log.info("菜品批量删除,{}",ids);
dishService.deleteBatch(ids);
//将所有的菜品缓存数据清理掉,所有以dish_开头
cleanCache("dish_*");
return Result.success();
}
/**
* 根据id查询菜品和对应的口味数据
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询菜品")
public Result<DishVO> getById(@PathVariable Long id){
log.info("根据id查询菜品:{}",id);
DishVO dishVO = dishService.getByIdWithFlavor(id);
return Result.success(dishVO);
}
/**
* 修改菜品
* @param dishDTO
* @return
*/
@PutMapping
@ApiOperation("修改菜品")
public Result update(@RequestBody DishDTO dishDTO){
log.info("修改菜品:{}",dishDTO);
dishService.updateWithFlavor(dishDTO);
//将所有的菜品缓存数据清理掉,所有以dish_开头
cleanCache("dish_*");
return Result.success();
}
/**
* 菜品的起售停售
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("菜品的起售停售")
public Result<String> startOrStop(@PathVariable Integer status,Long id){
log.info("菜品的起售停售:{},{}",status == 1 ? "起售" : "停售",id);
dishService.startOrStop(status,id);
//将所有的菜品缓存数据清理掉,所有以dish_开头的key
cleanCache("dish_*");
return Result.success();
}
/**
* 根据分类id查询菜品
*
* @param categoryId
* @return
*/
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public Result<List<Dish>> list(Long categoryId) {
List<Dish> list = dishService.list(categoryId);
return Result.success(list);
}
/**
* 清理缓存数据
* @param patten
*/
private void cleanCache(String patten){
Set keys = redisTemplate.keys(patten);
redisTemplate.delete(keys);
}
}
·测试
我们停售之后也把相应的缓存数据清理掉,然后重新查询数据库,它就变成这个样子了。