SpringCache
SpringCache是一个框架实现了基本注解的缓存功能,只需要简单的添加一个@EnableCaching 注解就能实现缓存功能
- SpringCache框架只是提供了一层抽象,底层可以切换
CacheManager接口的不同实现类即使用不同的缓存技术,默认的实现是ConcurrentMapCacheManager ConcurrentMapCacheManager是基于内存存储数据的,所以重启服务后缓存数据就会消失
| CacheManger | 描述 | 
|---|---|
| EhCacheCacheManager | 使用EhCache作为缓存技术 | 
| GuavaCacheManager | 使用Googke的GuavaCache作为缓存技术 | 
| RedisCacheManager | 使用Rdis作为缓存技术 | 
环境准备
 
第一步: 定义实体类User且实现序列化接口
@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String name;
    private int age;
    private String address;
}
 
第二步: 定义Mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User>{
}
 
第三步: 定义UserService接口及其实现类
public interface UserService extends IService<User> {
    
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    
}
 
第四步: 定义接口
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    // 默认的实现是ConcurrentMapCacheManager
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private UserService userService;
}
 
第五步: 开启缓存注解功能
@Slf4j
@SpringBootApplication
// 开启缓存注解功能
@EnableCaching
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}
 
SpringCache常用注解
因为缓存的数据key一定是唯一的,所以key支持SpEL表达式来动态的计算key(条件判断也支持SpEL表达式)
#result: 代表方法的返回值,如#result.id表示获取返回值对象的id属性值作为key#root: 代表整个方法对象,如#root.args[0].id表示获取方法的第一个参数的id属性值作为key#p[i]: 代表方法的参数,如p[0].id表示获取方法的第一个参数的id属性值作为key#方法参数名: 代表方法的参数,如#user.id获取参数user对象的id属性值作为key
condition和unless的区别
condition: 表示满足条件才进行缓存,不支持SpEL表达式中的#resultunless: 表示满足条件不进行缓存,支持SpEL表达式中的#result
| 注解 | 说明 | 
|---|---|
| @EnableCaching | 开启缓存注解功能 | 
| @Cacheable | 在方法执行前spring先查看缓存中是否有数据,如果有数据则直接返回缓存数据;若没有数据调用方法并将方法返回值放到缓存中(查询方法) | 
| @CachePut | 将方法的返回值放到缓存中(适合新增的方法) | 
| @CacheEvict | 将一条或者多条数据从缓存中删除(适合删除和更新的方法啊) | 
@CachePut(新增)
 
@CachePut主要针对方法配置,能够根据方法的请求参数将方法的返回值进行缓存,每次都会触发真实方法的调用
| 注解 | 说明 | 举例 | 
|---|---|---|
| value | 指定缓存的名称必须指定至少一个 | @Cacheable(value=”mycache”)或者@Cacheable(value=(“cache7”, “cache2”] | 
| key | 指定缓存的key(可以为空),但必须是动态唯一的,表示某类缓存中的一个具体数据 | @Cacheable(value=”testcache”,key=”#userName”) | 
| condition | 指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) | 
测试新增的方法将方法的返回值进行缓存

@CachePut(value="userCache",key="#user.id")
@PostMapping
public User save(User user){
    userService.save(user);
    return user;
}
 
查看ConcurrentMapCacheManager中缓存的结果

@CachEvict(删除)
 
@CachEvict主要针对方法配置,能够根据一定的条件将缓存中的数据进行清空
| 注解 | 说明 | 举例 | 
|---|---|---|
| value | 缓存的名称必须指定且至少一个 | @Cacheable(value=”mycache”)或者@Cacheable(value={“cache1”, “cache2”] | 
| key | 指定缓存的key(可以为空),但必须是动态唯一的 | @Cacheable(value=”testcache”,key=”#userName”) | 
| condition | 指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) | 
| allEntries | 是否清空某类缓存下的所有数据,默认为false | @CachEvict(value=”testcache”,allEntries=true) | 
| beforelnvocation | 是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value=”testcache”, beforelnvocation=true) | 
测试删除的方法清楚缓存中指定的key

@CachEvict(value="userCache",key="#user.id")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
    userService.removeById(id);
}
 
测试更新的方法清楚缓存中指定的key

@CachEvict(value="userCache",key="#id")
@PutMapping
public User update(User user){
    userService.updateById(user);
    return user;
}
 
@Cacheable(查询)
 
@Cacheable注解主要针对方法配置,如果缓存中没有数据能够根据方法的请求参数对方法结果进行缓存,如果缓存中有数据则不会调用方法
- 如果查询的数据在数据库中也查询不到则会缓存一个null,这样下次再查询这个数据时直接返回null,避免缓存穿透
 
| 注解 | 说明 | 举例 | 
|---|---|---|
| value | 指定缓存的名称表示一类缓存,每个缓存名称下可以存储多个key | @Cacheable(value=”mycache”)或者@Cacheable(value=(“cache7”, “cache2”] | 
| key(唯一) | 指定缓存数据的key(可以为空),表示某类缓存中的一个具体数据 | @Cacheable(value=”testcache”,key=”#userName”) | 
| condition | 指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) | 
| unless | 指定缓存的条件(可以为空)返回true或者false,满足条件不进行缓存 | @Cacheable(value=”testcache”,unless=”#userName.length()>2”) | 
测试根据id查询的方法,如果缓存中没有数据则将方法返回值进行缓存,如果缓存中有对应数据则不调用方法直接返回缓存的数据

@Cacheable(value="userCache",key="#id")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}
// 查询结果为null不缓存,condition不支持#result
@Cacheable(value="userCache",key="#id",unless="#result==null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}
 
测试根据多个条件进行查询的方法,不同的查询条件对应不同的缓存数据

@Cacheable(value="userCache",key="#user.id+'_'+#user.name")//查询条件和id和name有关
@GetMapping("/list")
public List<User> list(User user){
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(user.getId() != null,User::getId,user.getId());
    queryWrapper.eq(user.getName() != null,User::getName,user.getName());
    List<User> list = userService.list(queryWrapper);
    return list;
}
 
查询缓存的结果

使用SpringCache基于redis
使用步骤
 
第一步: 在SpringBoot项目中使用缓存技术只需要在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存技术支持即可
- 如果想使用SpringCache的基本功能只需要导入
spring-context依赖即可(导入spring-boot-starter-web会自动传递) 
<!--使用Redis作为缓存技术,里面包含CacheManager接口的实现类-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--对SpringCache中CacheManager接口的实现类进行了扩展-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
 
第二步: 在application.yml文件中配置redis相关的配置
spring:
  redis:
    host: 101.XXX.XXX.160 #redis服务所在地址
    password: root
    port: 6379
    database: 0
  cache:
    redis:
      time-to-live: 3600000 #设置缓存有效期为一小时(单位毫秒),如果不设置则一直存活
 
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    // 底层实现是RedisCacheManager
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private UserService userService;
}
 
第三步: 在启动类上加@EnableCaching注解表示开启缓存注解功能
@Slf4j
@SpringBootApplication
// 开启缓存注解功能
@EnableCaching
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}
 
第四步: 在Controller的方法上加上@Cacheable,@CachePut,@CacheEvict缓存注解进行缓存操作

// 查询结果为null不缓存,condition不支持#result
@Cacheable(value="userCache",key="#id",unless="#result==null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}
                


















