在上一篇文章 (《SpringBoot(二十四) 整合 Redis》)中, 已经实现了 Spring Boot 对 Redis 的整合, 既然已经讲到 Cache 了, 今天就介绍介绍缓存注解. 各家互联网产品现在数据量越来越大, 其快速增长造成网络拥塞和服务器超载, 导致客户访问延迟增大, 服务质量日益显现出来. 缓存技术被认为是减轻服务器负载, 降低网络拥塞, 增强可扩展性的有效途径之一.
v 概念介绍
Spring 为我们提供了几个注解来支持 Spring Cache. 其核心主要是 @Cacheable 和 @CacheEvict. 使用 @Cacheable 标记的方法在执行后 Spring Cache 将缓存其返回结果, 而使用 @CacheEvict 标记的方法会在方法执行前或者执行后移除 Spring Cache 中的某些元素. 下面我们将来详细介绍一下 Spring 基于注解对 Cache 的支持所提供的几个注解.
Spring Cache 常见概念介绍
名称 | 解释 |
---|---|
Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache 等 |
CacheManager | 缓存管理器,管理各种缓存(cache)组件 |
@Cacheable | 主要针对方法配置,能够根据方法的请求参数对其进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存。 与 @Cacheable 区别在于是否每次都调用方法,常用于更新 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据时 key 生成策略 |
serialize | 缓存数据时 value 序列化策略 |
@CacheConfig | 统一配置本类的缓存注解的属性 |
注解 (@Cacheable/@CachePut/@CacheEvict) 的主要参数
名称 | 解释 | example |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | e.g. @Cacheable(value=”mycache”) 或者 < br ztid="110" ow="0" oh="0">@Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则缺省按照方法的所有参数进行组合 | e.g. @Cacheable(value=”testcache”,key=”#id”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存 / 清除缓存 | e.g.@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存。当条件结果为 TRUE 时,就不会缓存。 | e.g.@Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
allEntries (@CacheEvict ) | 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存 | e.g. @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation (@CacheEvict) | 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 < br ztid="138" ow="0" oh="0">执行抛出异常,则不会清空缓存 | e.g. @CachEvict(value=”testcache”,beforeInvocation=true) |
v 准备工作
1.1 引入依赖 pom.xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
激活启动类注解 @EnableCaching
v 实战演练
2.1 添加 service 层
- package com.demo.service;
- import com.demo.pojo.UserDetails;
- /**
- * Created by toutou on 2019/1/20.
- */
- public interface CacheService {
- UserDetails getUserDetailsByUid(int uid);
- UserDetails updateUserInfo(UserDetails userDetails);
- int delUserInfoById(int uid);
- }
- package com.demo.service;
- import com.demo.dao.UserDetailsMapper;
- import com.demo.pojo.UserDetails;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.cache.annotation.CacheEvict;
- import org.springframework.cache.annotation.CachePut;
- import org.springframework.cache.annotation.Cacheable;
- import org.springframework.stereotype.Service;
- /**
- * Created by toutou on 2019/1/20.
- */
- @Service
- public class CacheServiceImpl implements CacheService{
- @Autowired
- UserDetailsMapper userDetailsMapper;
- @Override
- @Cacheable(value = "user_details", key = "#uid", unless="#result == null")
- public UserDetails getUserDetailsByUid(int uid){
- System.out.println("Cacheable 有请求过来了");
- UserDetails userDetails = userDetailsMapper.getUserDetailsByUid(uid);
- return userDetails;
- }
- @Override
- @CachePut(value = "user_details", key = "#user.id")
- public UserDetails updateUserInfo(UserDetails user){
- System.out.println("CachePut 有请求过来了");
- if(userDetailsMapper.updateByPrimaryKeySelective(user)> 0) {
- // 这里也可以直接在 updateByPrimaryKeySelective 的方法里, 修改后直接查询出该记录返回 UserDetails 实例, 看需求.
- user = userDetailsMapper.getUserDetailsByUid(user.getId());
- return user;
- }else{
- return null;
- }
- }
- @Override
- @CacheEvict(value = "user_details", key = "#uid")
- public int delUserInfoById(int uid){
- System.out.println("CacheEvict 有请求过来了");
- return userDetailsMapper.deleteByPrimaryKey(uid);
- }
- }
unless="#result == null" 是指当查询为空时, 不缓存, 默认是空也会缓存.
2.2 添加 CacheController
- package com.demo.controller;
- import com.demo.pojo.UserDetails;
- import com.demo.service.CacheService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.RestController;
- /**
- * Created by toutou on 2019/1/20.
- */
- @RestController
- @Slf4j
- public class CacheController {
- @Autowired
- CacheService cacheService;
- @RequestMapping(value = "/cache/getuserbyid")
- public UserDetails getUserDetailsByUid(int uid){
- try {
- return cacheService.getUserDetailsByUid(uid);
- }catch (Exception e){
- System.out.println(e.toString());
- return null;
- }
- }
- @RequestMapping(value = "/cache/updateuserinfo")
- public int updateUserInfo(int uid, String city){
- UserDetails userDetails = new UserDetails();
- userDetails.setId(uid);
- userDetails.setCity(city);
- userDetails = cacheService.updateUserInfo(userDetails);
- return userDetails == null ? 0 : userDetails.getUid();
- }
- @RequestMapping(value = "/cache/deluserinfobyid")
- public int delUserInfoById(int uid){
- return cacheService.delUserInfoById(uid);
- }
- }
2.3 实现 Serializable 接口
v 效果展示
3.1 Cacheable 效果
当我们本地请求 http://localhost:8081/cache/getuserbyid?uid=5 接口时, 可以看到控制台输出 Cacheable 有请求过来了, 而后续再次请求该接口时, 不会再输出 Cacheable 有请求过来了, 这是因为直接走了缓存机制了, CacheServiceImpl 的方法不再被调用.
通过 Redis 可以看到, user_details::5 的记录已被创建.
3.2 CachePut 效果
当我们本地请求 http://localhost:8081/cache/updateuserinfo?uid=5&city = 首都 接口时, 将更新数据库和 Redis 中对应的字段值.
查询接口, 更新成功. 控制台再次输出 Cacheable 有请求过来了
3.3 CacheEvict 效果
当我们本地请求 http://localhost:8081/cache/deluserinfobyid?uid=5 接口时, 将删除数据中和 Redis 中的数据.
v 博客总结
Redis 和 @Cacheable,@CachePut,@CacheEvict 结合使用, 效果挺好, 结合这篇和上篇文章 (《SpringBoot(二十四) 整合 Redis》), 可以尝试着结合使用试试.
v 源码地址
作 者: 请叫我头头哥
来源: https://www.cnblogs.com/toutou/p/cacheable.html