前言
本篇博客用于记录苍穹外卖Day07缓存商品、购物车的学习
缓存商品
缓存菜品
我们现在想要查询菜品数据,全由数据库查询而来,如果用户端访问量过大,数据库压力会很大,查询速度变慢。
解决方法:使用Redis来缓存菜品,减少查询数据库的操作(因为Redis是基于内存存储,相较于基于磁盘存储,使用Redis查询非常速度快)。
实现逻辑:
如下图所示,在我们查询菜品时,先去看缓存中是否存在,存在的话就从缓存中读取数据,不存在再去数据库中查询,同时将查询到的数据存进redis
实现步骤:
- 把每个分类下的菜品保存一份缓存数据(key为分类,value为菜品)
操作代码按照老师的来就好,但一定要注意一个地方,我们在RedisConfiguration中不能设置value的序列化器,要不然会报数据类型错误。
- 数据库中菜品有变更及时清理缓存(管理端的删除、修改、起停售、新增)
清理缓存除了新增菜品处我们只需删除特定的缓存数据,在其他操作中因为要删除特定的key会非常麻烦,这里为了简化就将全部的缓存数据删除了。
缓存套餐
在介绍缓存套餐前先介绍一下Spring Cache
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要一个注解即可完成缓存功能。
Spring Cache不仅可以使用Redis进行缓存,还可以使用EHCache、Caffeine完成缓存功能。导入Spring Cache的同时导入你想使用的缓存即可(我们这里导入了Spring Data Redis)
Spring Cache提供的常用注解:
注解 | 功能 |
---|---|
@EnableCaching | 开启缓存注解功能,通常加在启动类上 |
@Cacheable | 加在方法上,在方法执行前先查询缓存中是否存在缓存数据,存在数据直接将数据返回;没有缓存数据,通过反射调用方法并将方法的返回值放到缓存中 |
@CachePut | 将方法的返回值放到缓存中 |
@CacheEvict | 将一条或多条数据从缓存中删除 |
- 关于CachePut注解。如下代码,cacheNames表示缓存的名称,通常与业务相关,key = "#user.id"表示动态取到此时user的id与cacheName动态拼成redis的key, 若此时的#user.id为1,最终的redis中的key为userCache::1
@PostMapping
@CachePut(cacheNames = "userCache",key = "#user.id")
public User save(@RequestBody User user){
userMapper.insert(user);
return user;
}
- 关于Cacheable注解。如下代码,因为这里方法的参数就是我们要的id,所以key = “#id”,若此时的id为1,redis中的key就为userCache::1
@GetMapping
@Cacheable(cacheNames = "userCache",key = "#id")
public User getById(Long id){
User user = userMapper.getById(id);
return user;
}
- 关于CacheEvict注解。如下代码,当我们只需根据id删除一条数据时,意味着我们只需要删除一条缓存,key = “#id”;但当我们要批量删除时,这时用的就是allEntries = true,表示将userCache包下所以的缓存删除
@DeleteMapping
@CacheEvict(cacheNames = "userCache",key = "#id")
public void deleteById(Long id){
userMapper.deleteById(id);
}
@DeleteMapping("/delAll")
@CacheEvict(cacheNames = "userCache",allEntries = true)
public void deleteAll(){
userMapper.deleteAll();
}
接下来正式进入到缓存套餐的开发,缓存套餐的开发有三个步骤:
- 引入依赖
- 在启动类上加上@EnableCaching
- 在user、admin上涉及缓存的操作方法上加上注解
根据老师的讲解来即可,这里就不提供代码了
购物车
添加购物车
该功能的实现非常有意思,来重点分析一下:
-
首先我们要知道的是一次添加商品到购物车的操作只能是添加菜品或者添加套餐。
-
根据上述接口文档,我们得知请求参数是给我们提供好的ShoppingCartDto,controller如下
@RestController
@Slf4j
@ApiOperation("购物车相关接口")
@RequestMapping("/user/shoppingCart")
public class ShoppingCartController {
@Autowired
private ShoppingCartService shoppingCartService;
@PostMapping("/add")
@ApiOperation("添加购物车")
public Result add(@RequestBody ShoppingCartDTO shoppingCartDTO){
log.info("添加购物车:{}",shoppingCartDTO);
shoppingCartService.add(shoppingCartDTO);
return Result.success();
}
}
-
service层的代码就省略了
-
service实现类的代码就非常有意思了。新增购物车,我们要分三步:1.查看购物车的商品是否已经存在。2.存在的话商品数量直接数量加一。3.不存在商品插入一条购物车数据。
-
我们先来分析3,商品不存在,那么我们就要在将其加入到购物车,在此之前先判断它是菜品还是套餐,是菜品就从菜品表中查数据封装好ShoppingCart,是套餐就从套餐表中查数据封装好ShoppingCart,再插入到购物车表;接着分析1,我们封装好一个ShoppingCart对象后去购物车表中查询,因为此时我们添加的是一个菜品或一个套餐,所以在购物车表中满足条件的数据要么没有(对应3不存在这个商品),要么只有一条(对应2存在这个商品);最后分析2,我们只需将这条查到的购物车数据的number加一即可。
@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
@Autowired
private ShoppingCartMapper shoppingCartMapper;
@Autowired
private DishMapper dishMapper;
@Autowired
private SetmealMapper setmealMapper;
@Override
public void add(ShoppingCartDTO shoppingCartDTO) {
ShoppingCart shoppingCart=new ShoppingCart();
BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
//通过ThreadLocal获取登录时的userId
Long userId= BaseContext.getCurrentId();
shoppingCart.setUserId(userId);
//先判断加入购物车的商品是否已经存在
//在这里我们是先去查询是否存在这么个购物车,由于我们是根据userId来查询的,所以查到的购物车要么没有,要么只有一个
List<ShoppingCart> list=shoppingCartMapper.list(shoppingCart);
//存在的话商品数量直接数量加一
if(list!=null&&list.size()>0){
ShoppingCart shoppingCart1=list.get(0);
shoppingCart1.setNumber(shoppingCart1.getNumber()+1);
shoppingCartMapper.updateNumber(shoppingCart1);
}
//不存在商品插入一条购物车数据
else{
//先判断是菜品还是套餐
//插入菜品菜品
if(shoppingCartDTO.getDishId()!=null){
Dish dish=dishMapper.getById(shoppingCart.getDishId());
shoppingCart.setName(dish.getName());
shoppingCart.setImage(dish.getImage());
shoppingCart.setAmount(dish.getPrice());
}
//插入套餐
if(shoppingCartDTO.getSetmealId()!=null){
Setmeal setmeal=setmealMapper.getById(shoppingCart.getSetmealId());
shoppingCart.setName(setmeal.getName());
shoppingCart.setImage(setmeal.getImage());
shoppingCart.setAmount(setmeal.getPrice());
}
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(LocalDateTime.now());
shoppingCartMapper.insert(shoppingCart);
}
}
}
- ShoppingCartMapper
@Mapper
public interface ShoppingCartMapper {
List<ShoppingCart> list(ShoppingCart shoppingCart);
@Update("update shopping_cart set number=#{number} where user_id=#{userId}")
void updateNumber(ShoppingCart shoppingCart);
@Insert("insert into shopping_cart (name,image,user_id,dish_id,setmeal_id,dish_flavor,number,amount,create_time) values " +
"(#{name},#{image},#{userId},#{dishId},#{setmealId},#{dishFlavor},#{number},#{amount},#{createTime})")
void insert(ShoppingCart shoppingCart);
}
- ShoppingCartMapper.xml
![29](E:\Takeout\图片\29.png)<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.ShoppingCartMapper">
<select id="list" resultType="com.sky.entity.ShoppingCart">
select * from shopping_cart
<where>
<if test="userId!=null">and user_id=#{userId}</if>
<if test="dishId!=null">and dish_id=#{dishId}</if>
<if test="setmealId!=null">and setmeal_id=#{setmealId}</if>
<if test="dishFlavor!=null">and dish_flavor=#{dishFlavor}</if>
</where>
</select>
</mapper>
查看和清空购物车就没什么好说的,跟着老师的来即可
删除购物车中一个商品
这是老师留的作业,这里给出代码
- controller
@PostMapping("/sub")
@ApiOperation("删除购物车中一件商品")
public Result sub(@RequestBody ShoppingCartDTO shoppingCartDTO){
log.info("删除购物车中一件商品");
shoppingCartService.sub(shoppingCartDTO);
return Result.success();
}
- serviceImpl,需要我们注意的是要判断商品的份数,份数大于1的话份数减1即可,份数等于1的话删除这条购物车记录(根据id删除)
@Override
public void sub(ShoppingCartDTO shoppingCartDTO) {
ShoppingCart shoppingCart=new ShoppingCart();
BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
Long userId= BaseContext.getCurrentId();
shoppingCart.setUserId(userId);
List<ShoppingCart> list=shoppingCartMapper.list(shoppingCart);
if(list!=null&&list.size()>0){
ShoppingCart shoppingCart1=list.get(0);
int number=shoppingCart1.getNumber();
//份数大于一份,number-1
if(number>1){
shoppingCart1.setNumber(number-1);
shoppingCartMapper.updateNumber(shoppingCart1);
}else{
//份数等于一份,删除这条数据
shoppingCartMapper.deleteById(shoppingCart1);
}
}
}
- mapper
@Delete("delete from shopping_cart where id=#{id}")
void deleteById(ShoppingCart shoppingCart1);