缓存(cache):是数据库和服务器之间,能够减轻数据库压力还有提升访问效率的一个中间层。
因为数据库在实际开发中,这个服务相对而言算是比较脆弱的,可能会因为访问流量过大还有并发一高就造成宕机了。
以Redis来举例说明啊!
首先客户端发送一个请求查询菜品到后端服务,然后后端服务先查缓存,如果缓存里面有对应菜品的东西那么就会直接返回到前端,如果缓存当中没有东西那么就会继续去查数据库,然后加载数据库的东西存入缓存,再返回给前端。
缓存中怎么存放数据的?
缓存中有五种数据类型:string、hash、List、set、zset。
一般啊,我们主要以string和list这两种方式为主,list直接存数据就可以了,string的话就是转Json字符串。
举个例子:我要传菜品,那么在缓存中,我就把每一个键当做一个菜品分类,value成了每一个菜品分类所对应的菜品。
(参考图)
以这段代码为例
这段Service层代码首先它没有处理过缓存是直接访问数据库的。
所以第一步先依赖注入redisTemplate
@Autowired
private RedisTemplate redisTemplate;
第二步:查询缓存
dishVOList = (List<DishVO>) redisTemplate.opsForValue().get(FRONT_DISH_CATEGORY_PREFIX + dish.getCategoryId());
第三步:
有,直接返回。
没有,就访问数据库。
if(!Collections.isEmpty(dishVOList)){
log.info("{}","从缓存中获取菜品数据");
return Result.success(dishVOList);
}
第四步:
数据库查询完成:放入缓存
log.info("{}","获取缓存");
try {
redisTemplate.opsForValue().set(FRONT_DISH_CATEGORY_PREFIX + dish.getCategoryId(),dishVOList,1, TimeUnit.DAYS);
} catch (Exception e) {
throw new RuntimeException(e);
}
这里对缓存异常的做了try{}cath{}(单独处理)的原因是为了不让缓存操作影响到主业务的处理。
缓存中的数据应当与数据库中的数据保持一致性,所以商家在对数据库里的数据进行增删改的时候,要做一件事情就是清除缓存。
其中增加只要在对数据库的操作完成后,删除缓存就可以了而删除操作可以先删缓存再删数据库反过来也可以。
//数据已经正常保存到数据库了,删除当前新增菜品对应分类下的菜品数据
try {
redisTemplate.delete(FRONT_DISH_CATEGORY_PREFIX + dish.getCategoryId());
} catch (Exception e) {
throw new RuntimeException(e);
}
// 二.处理业务
for (Long id : ids) {
Dish dish = dishMapper.findById(id);
if(StatusConstant.ENABLE.equals(dish.getStatus())) {
//1.启售,不能删除
throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
}
Integer count = setmealDishMapper.countByDishId(dish.getId());
if(count > 0) {
//2.有套餐关联该菜品,不能删除
throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
}//删除缓存数据
try {
redisTemplate.delete(FRONT_DISH_CATEGORY_PREFIX + dish.getCategoryId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//3.删除菜品关联口味数据
dishFlavorMapper.deleteByDishIds(ids);
//4.删除菜品
dishMapper.deleteByIds(ids);
// 三.封装数据
return Result.success(MessageConstant.DELETE_SUCCESS);
更新:
主要涉及到如果把一个菜品的菜品分类修改成另一个分类,就要两个分类的缓存一起删除。
@Override
public Result<String> update(DishDTO dishDTO) {
// 一.校验参数
//先获取原先分类id
Long id = dishDTO.getId();
Dish oldDish = dishMapper.findById(id);
Long oldDishCategoryId = oldDish.getCategoryId();
// 二.处理业务
// 1.修改菜品基本数据
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO, dish);
dishMapper.update(dish);
// 2.把原先关联的菜品口味数据删除
List<Long> ids = new ArrayList<>();
ids.add(dish.getId());
dishFlavorMapper.deleteByDishIds(ids);
// 3.把新的品味数据增加
List<DishFlavor> flavors = dishDTO.getFlavors();
if(!Collections.isEmpty(flavors)) {
flavors.forEach(item -> {
item.setDishId(dish.getId());
});
dishFlavorMapper.savaBatch(flavors);
}//原先分类下的数据必删
//删除缓存数据
try {
redisTemplate.delete(FRONT_DISH_CATEGORY_PREFIX + oldDishCategoryId);
} catch (Exception e) {
throw new RuntimeException(e);
}//更新分类下的数据也需要删
if(!oldDishCategoryId.equals(dish.getCategoryId())){
redisTemplate.delete(FRONT_DISH_CATEGORY_PREFIX + dish.getCategoryId());
}// 三.封装数据
return Result.success(MessageConstant.UPDATE_SUCCESS);
}