需求:Redis缓存对象数据减少服务器压力,提供快速查询性能。
案例实现(按需灵活使用!)
用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。
结果:系统响应慢、用户体验差
通过Redis来缓存菜品数据,减少数据库查询操作。
缓存逻辑分析:
每个套餐下的菜品保存一份缓存数据
数据库中菜品数据有变更时清理缓存数据
Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:
EHCache
Caffeine
Redis(常用)
Server配置起步依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId> ? ? ? ? ? ? ? ? <version>2.7.3</version>
</dependency>
在SpringCache中提供了很多缓存操作的注解,常见的是以下的几个:
注解 | 说明 |
---|---|
@EnableCaching | 开启缓存注解功能,通常加在启动类上 |
@Cacheable | 在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法返回值放到缓存中 |
@CachePut | 将方法的返回值放到缓存中 |
@CacheEvict | 将一条或多条数据从缓存中删除 |
在spring boot项目中,使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存支持即可。
2). @CachePut注解
@CachePut 说明:
作用: 将方法返回值,放入缓存
value: 缓存的名称, 每个缓存名称下面可以有很多key
key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
3). @Cacheable注解
@Cacheable 说明:
作用: 在方法执行前,spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
value: 缓存的名称,每个缓存名称下面可以有多个key
key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
4). @CacheEvict注解
@CacheEvict 说明:
作用: 清理指定缓存
value: 缓存的名称,每个缓存名称下面可以有多个key
key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法
实现步骤:
1). 导入Spring Cache和Redis相关maven坐标
2). 在启动类上加入@EnableCaching注解,开启缓存注解功能
3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
4). 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解
按照上述实现步骤:
1). 导入Spring Cache和Redis相关maven坐标
<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>
2). 在启动类上加入@EnableCaching注解,开启缓存注解功能
?
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 SkyApplication {
? ?public static void main(String[] args) {
? ? ? ?SpringApplication.run(SkyApplication.class, args);
? ? ? ?log.info("server started");
? }
}
3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
/**
? ? * 条件查询
? ? *
? ? * @param categoryId
? ? * @return
? ? */
? ?@GetMapping("/list")
? ?@ApiOperation("根据分类id查询套餐")
? ?@Cacheable(cacheNames = "setmealCache",key = "#categoryId") //key: setmealCache::100
? ?public Result<List<Setmeal>> list(Long categoryId) {
? ? ? ?Setmeal setmeal = new Setmeal();
? ? ? ?setmeal.setCategoryId(categoryId);
? ? ? ?setmeal.setStatus(StatusConstant.ENABLE);
?
? ? ? ?List<Setmeal> list = setmealService.list(setmeal);
? ? ? ?return Result.success(list);
? }
4). 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解
/**
? ? * 新增套餐
? ? *
? ? * @param setmealDTO
? ? * @return
? ? */
? ?@PostMapping
? ?@ApiOperation("新增套餐")
? ?@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")//key: setmealCache::100
? ?public Result save(@RequestBody SetmealDTO setmealDTO) {
? ? ? ?setmealService.saveWithDish(setmealDTO);
? ? ? ?return Result.success();
? }
/**
? ? * 批量删除套餐
? ? *
? ? * @param ids
? ? * @return
? ? */
? ?@DeleteMapping
? ?@ApiOperation("批量删除套餐")
? ?@CacheEvict(cacheNames = "setmealCache",allEntries = true)
? ?public Result delete(@RequestParam List<Long> ids) {
? ? ? ?setmealService.deleteBatch(ids);
? ? ? ?return Result.success();
? }
/**
? ? * 修改套餐
? ? *
? ? * @param setmealDTO
? ? * @return
? ? */
? ?@PutMapping
? ?@ApiOperation("修改套餐")
? ?@CacheEvict(cacheNames = "setmealCache",allEntries = true)
? ?public Result update(@RequestBody SetmealDTO setmealDTO) {
? ? ? ?setmealService.update(setmealDTO);
? ? ? ?return Result.success();
? }
?
? ?/**
? ? * 套餐起售停售
? ? *
? ? * @param status
? ? * @param id
? ? * @return
? ? */
? ?@PostMapping("/status/{status}")
? ?@ApiOperation("套餐起售停售")
? ?@CacheEvict(cacheNames = "setmealCache",allEntries = true)
? ?public Result startOrStop(@PathVariable Integer status, Long id) {
? ? ? ?setmealService.startOrStop(status, id);
? ? ? ?return Result.success();
? }
通过前后端联调方式来进行测试,同时观察redis中缓存的套餐数据。和缓存菜品功能测试基本一致,不再赘述。