SpringBoot缓存
spring定义了Cache和CacheManager两个接口来统一管理不同的缓存技术,同时也支持使用JCache(JSR-107)注解来简化我们开发
- Cache:缓存接口,定义缓存操作,实现有:RedisCache,EhCacheCache,ConcurrentMapCache等
- CacheManager:缓存管理器,管理各种缓存(Cache)组件
几个常见的注解
缓存注解 | 解释 |
@Cacheable | 主要配置在方法上,根据方法的请求参数对其结果进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 方法被调用的同时,将结果缓存 |
@EnableCaching | 开启基于注解的缓存 |
SpringBoot缓存的运行原理
缓存的自动配置类CacheAutoConfiguration导入了CacheConfigurationImportSelector
其为我们导入了十个缓存配置类
默认生效的是SimpleCacheConfiguration
其给容器中注册了一个CacheManager:ConcurrentMapCacheManager
获取和创建ConcurrentMapCacheManager类型的缓存组件,将数据保存在ConcurrentMap中
运行流程:
1.方法运行之前,先去查询cache缓存组件,按照cacheName指定的名字获取,第一次获取缓存如果没有cache组件会自动创建出来
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createConcurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
2.去cache中按照key查找缓存的内容,key默认就是方法的参数
protected Object lookup(Object key) {
return this.store.get(key);
}
3.没有查找到缓存就调用目标方法,也就是去查找数据库
4.将找到的结果放进缓存中
public void put(Object key, @Nullable Object value) {
this.store.put(key, toStoreValue(value));
}
@Cacheable注解总的来说就是其标注的方法执行之前先来检查缓存中有没有数据,没有就去数据库中查并将结果放进缓存
缓存实例
1.开启基于注解的缓存
@SpringBootApplication
@EnableCaching//开启基于注解的缓存
@MapperScan(value = "com.lb.springboot.mapper")
public class SpringbootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootCacheApplication.class, args);
}
}
2.在方法上标注@Cacheable并设置缓存名
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
@Cacheable(value = "getEmp")
public Employee getEmp(int id){
System.out.println("查询用户ID:"+id);
return employeeMapper.getEmp(id);
}
}
3.效果展示
@Cacheable
第一次获取员工信息时,因为没有缓存在没有该信息,所以会执行方法去数据库查找,并将结果放进缓存中
第二次获取时,因为缓存已经有该信息,所以就不需要执行方法去数据库查找而是直接从缓存中获取
@CachePut
在方法上标注@CachePut并设置缓存名
@CachePut(value = "emp",key = "#result.id")
public Employee updateEmp(Employee employee){
System.out.println("更新用户ID:"+employee.getId());
employeeMapper.updateEmp(employee);
return employee;
}
效果
每次调用方法都会执行
并且将更新后的数据保存在缓存中
CacheEvict
在方法上标注@CacheEvict并设置要删除的key
@CacheEvict(value = "emp",key = "#id")
public void deleteEmp(int id){
System.out.println("deleteEmp: "+id);
}
效果
会把缓存中对应的key删除
随后获取数据时,因为缓存中该数据被删除了,所以需要重新调用方法去数据库查询
springboot整合redis
导入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
启动redis服务和连接redis
springboot中redis操作主要有两大类
- RedisTemplate<Object,Object>
- StringRedisTemplate<String,String>
StringRedisTemplate继承RedisTemplate
redis支持String,Hash,Set,List,Zset五大类型,这里只测试List和String,其他类型的方法都是大同小异
public class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void contextLoads() {
stringRedisTemplate.opsForValue().set("msg","redis" );
System.out.println(stringRedisTemplate.opsForValue().get("msg"));
public class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void contextLoads() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
stringRedisTemplate.opsForList().leftPushAll("list",list );
System.out.println(stringRedisTemplate.opsForList().index("list",2 ));
}
在请求中使用redis
@RestController
public class cacheController {
@Autowired
EmployeeService employeeService;
@GetMapping("/getEmp/{id}")
public Employee get(@PathVariable("id") int id){
Employee employee = employeeService.getEmp(id);
return employee;
}
}
注意把对象存进redis中时需要序列化
请求
@RestController
public class cacheController {
@Autowired
EmployeeService employeeService;
@GetMapping("/getEmp/{id}")
public Employee get(@PathVariable("id") int id){
Employee employee = employeeService.getEmp(id);
return employee;
}
}
完整代码在我的GitHub