出现问题:
当热点数据被并发且大量的访问时,将有大量的请求发送到数据库,数据库的压力会随之增大,从而产生一系列的问题
解决办法:
我们可以将数据加载到Redis缓存中,从而请求可以直接在缓存获取数据,减轻数据库的压力
大体思路:
实现方式一:Spring Data Redis
前言:
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
网址:Spring Data Redis官网
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
*
V
a
l
u
e
O
p
e
r
a
t
i
o
n
s
:简单
K
−
V
操作
S
t
r
i
n
g
数据操作
\color{#FF0000}{ValueOperations:简单K-V操作String数据操作}
ValueOperations:简单K−V操作String数据操作
*
S
e
t
O
p
e
r
a
t
i
o
n
s
:
s
e
t
类型数据操作
\color{#FF0000}{SetOperations:set类型数据操作}
SetOperations:set类型数据操作
*
Z
S
e
t
O
p
e
r
a
t
i
o
n
s
:
z
s
e
t
类型数据操作
\color{#FF0000}{ZSetOperations:zset类型数据操作}
ZSetOperations:zset类型数据操作
*
H
a
s
h
O
p
e
r
a
t
i
o
n
s
:针对
h
a
s
h
类型的数据操作
\color{#FF0000}{HashOperations:针对hash类型的数据操作}
HashOperations:针对hash类型的数据操作
*
L
i
s
t
O
p
e
r
a
t
i
o
n
s
:针对
l
i
s
t
类型的数据操作
\color{#FF0000}{ListOperations:针对list类型的数据操作}
ListOperations:针对list类型的数据操作
项目要求:Redis中菜品缓存数据KEY的设计:dish_分类id
一:导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二:添加缓存的代码例子
/**
* 根据分类id查询菜品
*
* @param categoryId 菜品分类id
* @return
*/
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public R<List<DishVO>> list(Long categoryId) {
//构造redis的key
String key="dish_"+categoryId;
//从Redis中获得缓存数据
List<DishVO> list= (List<DishVO>) redisTemplate.opsForValue().get(key);
//若缓存中存在该数据则直接返回,若没有执行添加缓存的操作
if (list != null) {
return R.success(list);
}
//封装查询条件
Dish dish = new Dish();
dish.setCategoryId(categoryId);
dish.setStatus(Dish.ON);
//根据查询条件查询对应菜品信息
list = dishService.listWithFlavor(dish);
//将查到的菜品信息和对应的缓存kay存储到Redis中
redisTemplate.opsForValue().set(key,list);
//返回查到的菜品信息
return R.success(list);
}
}
三:删除缓存
前提:当数据被更改或删除时,Redis缓存的数据也要同步更新
封装清理缓存的方法:
/**
* 抽取清除缓存的方法
* @param pattern
*/
private void clearCache(String pattern){
//删除无法进行模糊删除,所以先查询保存到set集合,再删除
Set keys = redisTemplate.keys(pattern);
redisTemplate.delete(keys);
}
进行删除操作:
clearCache("dish_*");
实现方式二:Spring Cache
前言
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache提供了一层抽象,底层可以切换不同的缓存实现。
CacheManager(缓存管理器)是Spring提供的各种缓存技术抽象接口。
针对不同的缓存技术需要实现不同的CacheManager:
RedisChacheManager常用注解
一:导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
二:在启动类上开启缓存注解功能
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
@EnableCaching//开启注解式缓存功能
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class, args);
log.info("server started");
}
}
三:查询方法使用
/**
* 条件查询
*
* @param categoryId
* @return
*/
@GetMapping("/list")
@ApiOperation("根据分类id查询套餐")
//redis的key 由cacheNames+key组成
@Cacheable(cacheNames = "SetmealCache",key = "#categoryId")
public R<List<Setmeal>> list(Long categoryId) {
Setmeal setmeal = new Setmeal();
setmeal.setCategoryId(categoryId);
setmeal.setStatus(StatusConstant.ENABLE);
List<Setmeal> list = setmealService.list(setmeal);
return R.success(list);
}
四:删除缓存
/**
* 新增套餐
* @param setmealDTO
* @return
*/
@PostMapping
@ApiOperation("新增套餐")
//删除所有SetmealCaChe
@CacheEvict(cacheNames = "SetmealCache",key = "#setmealDTO.categoryId")
public R save(@RequestBody SetmealDTO setmealDTO) {
setmealService.saveWithDish(setmealDTO);
return R.success();
}
添加缓存拓展
@PostMapping
@Cacheable(cacheNames = "SetmealCache",key = "#user.id")
//#result用于引用方法调用的结果。对与支持的包装器,例如Optional,@result指的是实际对象,而不是包装器
//@Cacheable(cacheNames = "SetmealCache",key = "#result.id")
//方法参数可以通过索引访问。例如,可以通过#root.args[1]、#p1或#a1访问第二个参数,如果该信息可用,也可以按名称访问参数
//@Cacheable(cacheNames = "SetmealCache",key = "#p0.id")
//@Cacheable(cacheNames = "SetmealCache",key = "#a0.id")
//方法名称(#root.methodName)和目标类(#root.targetClass)的快捷方式也可用
//@Cacheable(cacheNames = "SetmealCache",key = "#root.args[0].id")
public User save(@RequestBody User user){
userMapper.insert(user);
return user;
}
二种实现方法的区别
Spring Data Redis:虽然较注解来说复杂、麻烦但是对于一个方法中要进行多种数据缓存时,灵活性高
Spring Cache:简单快捷