目录
一、前言
1.1 问题引入
在同一个时间段内,向数据库进行大量操作(例如:添加大量的内容),就会频繁的查询数据库,导致数据库访问压力过大,最终导致系统响应慢、体验差
1.2 解决方法
使用redis缓存
二、Redis缓存
2.1 缓存的概念
缓存是数据交换的缓冲区(Cache),是数据存储(使用频繁的数据)的临时地方,相对来说他的读写性能比较高。当用户查询数据,首先在缓存中寻找,如果找到了则直接执行;如果找不到则去数据库中查找
优点:
- 加快了响应速度
- 减少了对数据库的读操作,数据库的压力降低
缺点:
-
内存容量相对硬盘小
-
缓存中的数据可能与数据库中数据不一致
-
内存断电就会清空数据,造成数据丢失
2.2 实现思路
2.2.1 流程图
2.2.2 具体实战
如何使用redis可以浏览博主的另一篇文章:在java中操作redis数据库-优快云博客
实战代码:
@RestController("userDishController")
@RequestMapping("/user/dish")
@Slf4j
@Api(tags = "C端-菜品浏览接口")
public class DishController {
@Autowired
private DishService dishService;
@Autowired
private RedisTemplate redisTemplate;
/*根据分类id查询菜品*/
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public Result<List<DishVO>> list(Long categoryId) {
//构造redis中的key,规则:dish_分类id
String key = "dish_" + categoryId;
//查询redis中是否存在菜品数据(放进去的是什么类型的,取出来就是什么类型)
List<DishVO> list = (List) 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);//查询起售中的菜品
//如果不存在,查询数据库,将查询到的数据放入redis中
list = dishService.listWithFlavor(dish);
redisTemplate.opsForValue().set(key,list);
return Result.success(list);
}
}
2.2.3 清除缓存数据
为了保证数据库和Redis中的数据保持一致,当数据库中发生变更时,缓存中需要清除,例如修改、删除、新增、启售、禁售操作
实战代码:
@PostMapping
@ApiOperation("新增菜品")
public Result save(@RequestBody DishDTO dishDTO){
log.info("新增菜品:{}",dishDTO);
dishService.saveWithFlavor(dishDTO);
//清除缓存数据
String key = "dish_"+dishDTO.getCategoryId();
redisTemplate.delete(key);
return Result.success();
}
@DeleteMapping
@ApiOperation("菜品的批量删除")
public Result delete(@RequestParam List<Long> ids){
log.info("菜品的批量删除:{}",ids);
dishService.deleteBatch(ids);
//清除缓存数据,把所有缓存删除,所有以dish_开头的key
Set keys = redisTemplate.keys("dish_*");
redisTemplate.delete(keys);
return Result.success();
}
三、使用 SpringCache 的注解
3.1 Spring Cache
3.1.1 介绍
Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。使用它可以简化我们缓存操作的代码。
Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:
EHCache
Caffeine
Redis(常用)
3.1.2 引入maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
3.1.3 常用注解
3.1.4 常用注解参数
value: 缓存管理器中配置的缓存的名称,这里可以理解为一个组的概念,缓存管理器中可以有多套缓存配置,每套都有一个名称,类似于组名,这个可以配置这个值,选择使用哪个缓存的名称,配置后就会应用那个缓存名称对应的配置。
key: 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。
在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存支持即可。
例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。
3.2 入门Demo
3.2.1 首先在启动类上加@EnableCaching注解
@Slf4j
@SpringBootApplication
@EnableCaching //开启缓存注解功能
public class CacheDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CacheDemoApplication.class,args);
log.info("项目启动成功...");
}
}
3.2.2 使用@CachePut注解
当前UserController的save方法是用来保存用户信息的,我们希望在该用户信息保存到数据库的同时,也往缓存中缓存一份数据,我们可以在save方法上加上注解 @CachePut,缓存的 value 为方法返回值。
作用: 将方法返回值,放入缓存
代码如下:
(主键返回)Mapper层中:
@Insert("insert into user(name,age) values (#{name},#{age})")
@Options(useGeneratedKeys = true,keyProperty = "id")
void insert(User user);
Controller层中:
@PostMapping
@CachePut(cacheNames = "userCache",key = "#user.id") //如果使用springCache缓存数据,key的生成是: userCache::(拼上key的值)
// @CachePut(value = "userCache",key = "#result.id") //对象导航
// @CachePut(value = "userCache",key = "#p0.id")
// @CachePut(value = "userCache",key = "#a0.id")
// @CachePut(value = "userCache",key = "#root.args[0].id")
public User save(@RequestBody User user){
userMapper.insert(user);
return user;
}
说明:key的写法如下
#user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;
#result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;
#p0.id:#p0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
#a0.id:#a0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
#root.args[0].id:#root.args[0]指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
3.2.3 使用@Cacheable注解
@GetMapping
@Cacheable(cacheNames = "userCache",key = "#id")
public User getById(Long id){
User user = userMapper.getById(id);
return user;
}
作用:在方法执行前,spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中,缓存的 value 为方法返回值。
3.2.4 使用@CacheEvict注解
@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();
}
作用:清理指定缓存 可以通过allEntries属性清理所有缓存