外卖开发(六)—— 高查询量数据的缓存
- 一、代码实现缓存
- 1、查询缓存
- 2、修改数据时删除缓存
- 二、spring cache注解实现
- 1、Cacaheable
- 2、CacheEvict
一、代码实现缓存
1、查询缓存
在查询的时候,先去redis中查找数据,如果存在则直接返回数据;否则就去数据库进行查找,并将查找结果存入redis中,并返回数据。(redis的key设置为categoryId)
@GetMapping("list")public Result<List<DishVO>> list(Long categoryId){//查询redis中是否存在数据 存在则直接去redis 否则去查数据库//构造keyString 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);//将数据放入redisredisTemplate.opsForValue().set(key,listVO);return Result.success(listVO);}
2、修改数据时删除缓存
如果数据库中数据更新,如删除、修改、增加等,需要对redis缓存进行删除,保持数据一致性。(redis的key设置为categoryId)
新增菜品中,只需对相应的数据进行删除。
/*** 新增菜品* @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缓存
/*** 批量删除菜品* @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
<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。如下图所示
/*** 根据分类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 指定为删除所有
/*** 新增套餐* @param setmealDTO* @return*/@PostMapping@ApiOperation("新增套餐")@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")public Result insertSetmeal(@RequestBody SetmealDTO setmealDTO){setmealService.addSetmeal(setmealDTO);return Result.success();}
/*** 修改套餐* @param setmealDTO* @return*/@PutMapping@ApiOperation("修改套餐")@CacheEvict(cacheNames = "setmealCache",allEntries = true)public Result update(@RequestBody SetmealDTO setmealDTO){setmealService.update(setmealDTO);return Result.success();}