外卖开发(六)------ 高查询量数据的缓存
- 一、代码实现缓存
- [二、spring cache注解实现](#二、spring cache注解实现)
一、代码实现缓存
1、查询缓存
在查询的时候,先去redis中查找数据,如果存在则直接返回数据;否则就去数据库进行查找,并将查找结果存入redis中,并返回数据。(redis的key设置为categoryId)
java
@GetMapping("list")
public Result<List<DishVO>> list(Long categoryId){
//查询redis中是否存在数据 存在则直接去redis 否则去查数据库
//构造key
String key = "dish_" + categoryId;
//查询redis中是否存在数据
List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);
if (list !=null && list.size()>0){
return Result.success(list);
}
//如果不存在,只能去数据库查找
Dish dish = new Dish();
dish.setCategoryId(categoryId);
dish.setStatus(StatusConstant.ENABLE); //查询起售中的商品
List<DishVO> listVO = dishService.listWithFlavor(dish);
//将数据放入redis
redisTemplate.opsForValue().set(key,listVO);
return Result.success(listVO);
}

2、修改数据时删除缓存
如果数据库中数据更新,如删除、修改、增加等,需要对redis缓存进行删除,保持数据一致性。(redis的key设置为categoryId)
新增菜品中,只需对相应的数据进行删除。
java
/**
* 新增菜品
* @param dishDTO
* @return
*/
@PostMapping
@ApiOperation("新增菜品")
public Result addDish(@RequestBody DishDTO dishDTO){
log.info("新增菜品:{}",dishDTO);
dishService.insertDish(dishDTO);
//清理缓存
String key = "dish_" + dishDTO.getCategoryId();
redisTemplate.delete(key);
return Result.success();
}
删除菜品、修改菜品涉及到复杂的数据库操作,为简化redis操作,直接删除所有redis缓存
java
/**
* 批量删除菜品
* @param ids
* @return
*/
@DeleteMapping
@ApiOperation("批量删除菜品")
public Result deleteDish(@RequestParam List<Long> ids){
dishService.deleteDish(ids);
//删除全部redis缓存
Set keys = redisTemplate.keys("dish_*"); //获取redis中所有的key------通配符dish_*获取,并删除全部
redisTemplate.delete(keys);
return Result.success();
}
二、spring cache注解实现
Spring Cache
是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache
提供了一层抽象,底层可以切换不同的缓存实现,例如:
EHCache
Caffeine
Redis
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.7.3</version>
</dependency>
1、Cacaheable
@Cacheable(cacheNames = "setmealCache",key = "#categoryId")
@Cacheable(cacheNames = "setmealCache",key = "#setmeal.id")
//如果形参是实体类对象,可以用 ". " 来获取属性值
@Cacheable中有两个参数,第一个是cacheNames,指定了redis数据库中的key值的前半部分(通用标识),第二个是唯一标识,可以动态指定方法形参中的属性值,比如将唯一的id作为Redis的key值的的后半部分,这样就可以唯一的标识为一个redis。
总结来说,@Cacheable
中指定的参数,可以表示为:"setmealCache::#categoryId",其中每一个冒号都代表一层,有两个冒号,且冒号中间没有东西,则表示为Empty。如下图所示
java
/**
* 根据分类id查询套餐
* @param categoryId
* @return
*/
@GetMapping("/list")
@ApiOperation("根据分类id查询套餐")
@Cacheable(cacheNames = "setmealCache",key = "#categoryId")
public Result<List<Setmeal>> list(Long categoryId){
Setmeal setmeal = new Setmeal();
setmeal.setCategoryId(categoryId);
setmeal.setStatus(StatusConstant.ENABLE);
List<Setmeal> list = setmealService.getByCategoryId(setmeal);
return Result.success(list);
}

2、CacheEvict
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")
删除指定的cache,cacheName和key一起指定Redis的key
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
删除cacheName下所有的cache,allEntires = true 指定为删除所有
java
/**
* 新增套餐
* @param setmealDTO
* @return
*/
@PostMapping
@ApiOperation("新增套餐")
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")
public Result insertSetmeal(@RequestBody SetmealDTO setmealDTO){
setmealService.addSetmeal(setmealDTO);
return Result.success();
}
java
/**
* 修改套餐
* @param setmealDTO
* @return
*/
@PutMapping
@ApiOperation("修改套餐")
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result update(@RequestBody SetmealDTO setmealDTO){
setmealService.update(setmealDTO);
return Result.success();
}