SpringBoot的Cacheable缓存入门
Posted a10615
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot的Cacheable缓存入门相关的知识,希望对你有一定的参考价值。
因为工作需要,最近开始学习SpringBoot。要使用缓存,就搜索了下SpringBoot的缓存方案,有自带的ConcurrentLinkedHashMap,还有主流的Guava、Caffeine、Ehcache
作为入门,先拿自身的来玩玩,也就是ConcurrentLinkedHashMap
一、ConcurrentLinkedHashMap的使用
先简单说一下,此缓存保存在内存中,如果关闭或重启服务,缓存将被清除。如果要长久保存,可以结合Redis
使用方式,很简单,抓住这几个注解关键词:@EnableCaching、@Cacheable、@CachePut、@CacheEvict
1.1 @EnableCaching
一般在启动基类上加上此注解,表示打开缓存功能
@SpringBootApplication
@EnableCaching // 打开缓存功能
public class DemoApplication
1.2 @Cacheable
用在获取并缓存数据的方法上,表示此方法有缓存功能。当调用此方法时,会先从缓存中查找
- 如果缓存里有,就直接返回,不会运行方法内部语句;
- 如果没有,则执行方法内部语句,然后把返回值缓存起来
/** 临时用HashMap当作数据库 */
private HashMap<Integer, UserBean> users = new HashMap<>();
@Cacheable(cacheNames = "cacheModel", key = "#id", unless = "#result == null")
public UserBean getById(int id)
System.out.println("CacheModel.getById:id=" + id);
UserBean user = new UserBean(id, "name_" + new Random().nextInt(100));
users.put(id, user);
return user;
1.3 @CachePut
用在更新缓存的方法上,表示更新缓存中的数据。
@CachePut(cacheNames = "cacheModel", key = "#user.id", unless = "#user == null")
public UserBean updateUser(UserBean user)
System.out.println("CacheModel.updateUser: user=" + user);
return users.put(user.getId(), user);
注意:更新缓存时,如果缓存里没有,会把
key=user.id,value=null
给缓存。所以最好在调用此方法前先确认缓存已存在,否则更新后再获取值为null
1.4 @CacheEvict
用在删除缓存的方法上,表示根据条件删除对应的缓存
@CacheEvict(cacheNames = "cacheModel", key = "#id")
public UserBean removeUser(int id)
System.out.println("CacheModel.removeUser: id=" + id);
return users.remove(id);
如果要清除cacheNames指定名称的所有缓存,增加参数:allEntries = true
@CacheEvict(cacheNames = "cacheModel", allEntries = true)
public void clear()
System.out.println("CacheModel.clear all");
二、应用
2.1 Bean
@Data
@ToString
@NoArgsConstructor
public class UserBean
private int id;
private String name;
public UserBean(int id, String name)
this.id = id;
this.name = name;
2.2 RestController
@RestController
@RequestMapping("/user")
public class UserController
@Autowired
private CacheModel model;
@GetMapping("/getById")
public ResponseEntity<UserBean> getById(@RequestParam("id") int id)
UserBean user = model.getById(id);
return new ResponseEntity<>(user, HttpStatus.OK);
@PutMapping("/update/id")
public ResponseEntity<UserBean> updateUser(@PathVariable("id") int id,
@RequestParam("name") String name)
UserBean user = new UserBean(id, name);
UserBean result = model.updateUser(user);
System.out.println("UserController.updateUser: result =" + result);
return new ResponseEntity<>(user, HttpStatus.OK);
@PutMapping("/update")
public ResponseEntity<UserBean> updateUser(@RequestBody UserBean user)
UserBean result = model.updateUser(user);
System.out.println("UserController.updateUser: result =" + result);
return new ResponseEntity<>(user, HttpStatus.OK);
@DeleteMapping("/del")
public ResponseEntity<UserBean> delete(@RequestParam("id") int id)
UserBean user = model.removeUser(id);
return new ResponseEntity<>(user, HttpStatus.OK);
@PostMapping("/clear")
public ResponseEntity<String> clear()
model.clear();
return new ResponseEntity<>("success", HttpStatus.OK);
2.3 测试
Windows下测试(Windows系统里,不能使用单引号'
,双引号"
里的引用必须用三个双引号"""
)
> curl http://localhost:8080/user/getById?id=11
> curl http://localhost:8080/user/update/16?name=name_16 -X PUT
# 或
> curl http://localhost:8080/user/update -X PUT -H "Content-Type:application/json" -d """"id""":11, """name""":"""name_json""""
> curl http://localhost:8080/user/del?id=11 -X DELETE
> curl http://localhost:8080/user/clear -X DELETE
三、无效原因
3.1 cacheNames无效
在application.properties中已经配置好了缓存名称,如果cacheNames
的值没包含在配置中,就会报错无效
spring.cache.cache-names=testModel, cacheModel
3.2 未被Spring代理
这是最最重要的一点,因为@Cacheable是Spring框架下的,如果未通过cglib生成代理,直接调用new对象出来的方法,就不会缓存了。一开始接触Spring,未理解Spring的AOP,直接写了个单例,结果就无效了
所以,如果遇到无效的情况,依次检查:
- 是否被Spring代理了。通过对象的名称来判断
model.getClass().getName()
,正确类似这种格式:CacheModel$$EnhancerBySpringCGLIB$$3b28ee6d
- 是否直接调用了类内部的缓存方法。在类的内部,方法A调用缓存方法B,是不会走动态代理的,所以也无效,如下。缓存方法必须通过外部来调用才有效
/** * 调用内部方法,缓存无效 */ public UserBean getUser(int id) return getById(id); @Cacheable(cacheNames = "cacheModel", key = "#id", unless = "#result == null") public UserBean getById(int id) ...
有的还可能跟缓存数据对象的Serializable序列化有关
参数
参数说明,请参考其它文章
参考
以上是关于SpringBoot的Cacheable缓存入门的主要内容,如果未能解决你的问题,请参考以下文章
Springboot集成Redis详细教程(缓存注解使用@Cacheable,@CacheEvict,@CachePut)