苍穹外卖-缓存和购物车
苍穹外卖-缓存
用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大
为了解决这个问题,我们通过Redis来缓存菜品数据,减少数据库的查询操作
当用户查询数据时,先找缓存中,如果没有再将数据库中数据查找到放入缓存中
当其他用户查询时,缓存中已经存在数据了
实现思路
每一个分类的菜品保存在一个缓存数据中(存在一个key中),使用分类id作为缓存的key
当数据库中的菜品发生变更时清理缓存数据
业务代码
Redis中的String类型并不是Java意义上的String字符串类型
我们使用Java对Redis的String类型数据进行存放,可以直接存放对象类型的数据,怎么存进去怎么取出来即可
其中的原理就是将对象数据进行一个序列化,然后存储,取出来的时候进行反序列化的过程
1 | |
数据变更
在对数据库中的菜品进行增删改的操作时,需要清理缓存数据
但无需清理掉所有的缓存数据,对哪个分类(Key)进行操作,就清理掉这个Key的缓存数据
1 | |
注:在存放缓存数据时,我们在Service层操作,而清空返回数据我们在Controller层操作(感觉在Service层操作也可以)
删除操作
在进行删除操作时,我们需要根据分类id清除缓存数据,但是我们删除时拿不到分类id,还要进行数据库查询之后再拿id就十分麻烦
所以我们在进行删除操作时,直接删除所有缓存数据即可
1 | |
修改操作
当修改一些菜品信息时,删除缓存数据就会很简单
但如果修改分类时,会影响到缓存中两个分类中的菜品数据
所以我们也是干掉所有的缓存数据
cleanCache()
抽取成为cleanCache方法
1 | |
Spring Cache
Spring提供了缓存功能的框架实现,只需要简单实用注解,就能实现缓存功能
Spring Cache底层可以切换不同的缓存实现:
- EHCache
- Caffeine
- Redis
有趣的是,我们并不需要针对不同的底层而具体编写配置文件,只需要导入Redis的Java依赖就会被SpringCache自动识别并应用
导入依赖
1 | |
常用注解
| 注解 | 说明 |
|---|---|
| @EnableCaching | 加在启动类上,用以开启注解功能 |
| @Cacheable | 在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法的返回值放到缓存中 |
| @CachePut | 将方法的返回值放到缓存中 |
| @CacheEvict | 将一条或多条数据从缓存中删除 |
key的生成
如果使用SpringCache缓存数据,key的生成与注解的属性cacheNames、key有关
cacheNames::key
在redis中,冒号分隔的字符会被逻辑分层
而key的值不可以是唯一的,否则所有缓存都会放到同一个key中
所以使用spEL(Spring表达式语言)来动态获取key
1 | |
直接使用参数对象的id也是没有问题的,操作缓存数据是等到方法执行玩才会操作,这样主键值会回显回来
spEL
| 表达式 | 说明 |
|---|---|
| #result | 当前方法的返回值 |
| #形参 | 获取方法的参数 |
| #p0 | 获取方法的第一个参数 |
| #a0 | 获取方法的第一个参数 |
| #root.arg[0] | 获取方法的第一个参数 |
代理对象
Spring Cache的本质是为加入注解的方法生成一个代理,在执行具体的方法前,先对Redis中的缓存进行一些操作
删除
除了使用@CacheEvict注解删除单个缓存数据之外,还能删除所有缓存数据
使用allEntries = true属性来控制是否删除所有key
1 | |
苍穹外卖-购物车功能
在购物车表中设计冗余字段,可以增加查询的效率
- 判断新增菜品/套餐在购物车是否存在
- 存在,则数量加一
- 不存在,则判断是套餐还是菜品
- 是套餐,则根据套餐查询信息,将套餐插入到购物车中
- 是菜品,则根据菜品查询信息,将菜品插入到购物车中