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@Autowiredprivate CacheManager cacheManager;@Autowiredprivate 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表达式中的#result
unless
: 表示满足条件不进行缓存,支持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: rootport: 6379database: 0cache:redis:time-to-live: 3600000 #设置缓存有效期为一小时(单位毫秒),如果不设置则一直存活
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {// 底层实现是RedisCacheManager@Autowiredprivate CacheManager cacheManager;@Autowiredprivate 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;
}