稷然如此

  • 首页
  • 文章分类
    • AI
    • Android
    • Java
    • Shell
    • Vue
    • C#
    • Python
    • 数据库
    • 组件
    • 其他
    • Game
  • 常用命令
    • Docker
    • Git
    • Linux
  • 操作系统
    • CentOS
    • Ubuntu
    • Windows
    • Kylin
  • 工具
    • IntelliJ IDEA
    • Visual Studio Code
稷然如此
不积跬步,无以至千里
  1. 首页
  2. 文章分类
  3. Java
  4. 正文

Spring Boot Cache

2023年7月11日 781点热度 0人点赞

@Cacheable

添加在方法上,缓存方法的执行结果。执行过程如下:
1.判断方法执行结果的缓存。如果有,则直接返回该缓存结果。
2.执行方法,获得方法结果。
3.根据是否满足缓存的条件。如果满足,则缓存方法结果到缓存。
4.返回方法结果。
常用属性:
cacheNames:缓存名。必填。[] 数组,可以填写多个缓存名。
values:和 cacheNames 属性相同,是它的别名。
key:缓存的 key 。允许空。
如果为空,则默认方法的所有参数进行组合。
如果非空,则需要按照 SpEL(Spring Expression Language) 来配置。例如说,@Cacheable(value = "users", key = "#id") ,使用方法参数 id 的值作为缓存的 key 。
SpEL(Spring Expression Language) 配置:
名字位置描述示例
methodNameroot object当前被调用的方法名#root.methodName
methodroot object当前被调用的方法#root.method.name
targetroot object当前被调用的目标对象#root.target
targetClassroot object当前被调用的目标对象类#root.targetClass
argsroot object当前被调用的方法的参数列表#root.args[0]
cachesroot object当前方法调用使用的缓存列表(如@Cacheable(value={"cache1","cache2"}),则有两个cache)#root.caches[0].name
argument nameevaluation context方法参数的名字,可以直接使用#参数名,也可以使用 #p0 或 #a0 的形式,0代表参数的索引#a0
resultevaluation context方法执行后的返回值(仅当方法执行后的判断有效)#result
condition:基于方法入参,判断要缓存的条件,允许空。
如果为空,则不进行入参的判断。

如果非空,则需要按照 SpEL(Spring Expression Language) 来配置。例如说,@Cacheable(condition="#id > 0") ,需要传入的 id 大于零。下面例子中#user.id%2==0,id为偶数时才对返回对象user进行缓存。

@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
	System.out.println("find user by user " + user);
	return user;
}
unless:基于方法返回,判断不缓存的条件。允许空。
如果为空,则不进行入参的判断。
如果非空,则需要按照 SpEL(Spring Expression Language) 来配置。例如说,@Cacheable(unless="#result == null") ,如果返回结果为 null ,则不进行缓存。
要注意,condition 和 unless 都是条件属性,差别在于前者针对入参,后者针对结果。
不常用属性:
keyGenerator:自定义 key 生成器 KeyGenerator Bean 的名字。允许空。如果设置,则 key 失效。
cacheManager:自定义缓存管理器 CacheManager Bean 的名字。允许空。一般不填写,除非有多个 CacheManager Bean 的情况下。
cacheResolver:自定义缓存解析器 CacheResolver Bean 的名字。允许空。
sync:在获得不到缓存的情况下,是否同步执行方法。
默认为 false ,表示无需同步。
如果设置为 true ,则执行方法时,会进行加锁,保证同一时刻,有且仅有一个方法在执行,其它线程阻塞等待。通过这样的方式,避免重复执行方法。注意,该功能的实现,需要参考第三方缓存的具体实现。

@CachePut

添加在方法上,缓存方法的执行结果。不同于 @Cacheable 注解,它的执行过程如下:
1.执行方法,获得方法结果。也就是说,无论是否有缓存,都会执行方法。
2.根据是否满足缓存的条件。如果满足,则缓存方法结果到缓存。
3.返回方法结果。
注解的属性,和 @Cacheable 注解的属性,基本一致,只少一个 sync 属性。
一般来说,使用方式如下:
@Cacheable
搭配读操作,实现缓存的被动写。
@Override
@Cacheable(value = {"menuById"}, key = "#id")
public Menu findById(String id) {
	Menu menu = this.getById(id);
	if (menu != null){
		System.out.println("menu.name = " + menu.getName());
	}
	return menu;
}
@CachePut
配置写操作,实现缓存的主动写。
每次都会触发真实方法的调用,根据返回值来更新缓存,所以如果更新方法返回值为void,则缓存为Null;如果是Boolean、Integer等其他非对象返回值,则会报错无法转换成xxx对象。
@Override
@CachePut(value = "menuById", key = "#menu.id")
public Menu ReviseById(Menu menu) {
	this.updateById(menu);
	return menu;
}

@CacheEvict

添加在方法上,删除缓存,一般用在更新或者删除的方法上。
相比 @CachePut 注解,它额外多了两个属性:
allEntries 属性,是否删除缓存名( cacheNames )下,所有 key 对应的缓存。默认为 false ,只删除指定 key 的缓存。
beforeInvocation 属性,是否在方法执行前删除缓存。默认为 false ,在方法执行后删除缓存。
删除某个分区下的所有数据
@CacheEvict(value = {"name1"}, allEntries = true)
删除多个Key的缓存
@Cacheable(cacheNames = "provinceId:info",key ="#provinceId" )
public List<AreaDTO> findCityList(String provinceId) {
	return areaRepository.findAllByParentIdAndDelFlagIsFalse(provinceId);
}

@Cacheable(cacheNames = "cityId:info",key ="#cityId" )
public List<AreaDTO> findOrganyList(String cityId) {
	return areaRepository.findAllByParentIdAndDelFlagIsFalse(cityId);
}

@Cacheable(cacheNames = "organId:info",key ="#organId" )
public List<AreaDTO> findStreetList(String organId) {
	return areaRepository.findAllByParentIdAndDelFlagIsFalse(organId);
}

@Cacheable(cacheNames = "areaCode:info",key = "#code")
public String findByCode(String code) {
	Area area = areaRepository.findFirstByCodeAndDelFlagIsFalse(code);
	if (area != null && StringUtils.isNotEmpty(area.getCode())) {
		return area.getName();
	}
	return code;
}

@Caching(evict ={
		@CacheEvict(cacheNames = "provinceId:info",allEntries = true),
		@CacheEvict(cacheNames = "organId:info",allEntries = true),
		@CacheEvict(cacheNames = "areaCode:info",allEntries = true),
		@CacheEvict(cacheNames = "cityId:info",allEntries = true)
})

public void refresh() {

}

@Caching

添加在方法上,可以组合使用多个 @Cacheable、@CachePut、@CacheEvict 注解。不太常用,可以暂时忽略。

@CacheConfig

添加在类上,共享如下四个属性的配置:
cacheNames
keyGenerator
cacheManager
cacheResolver

@EnableCaching

标记开启 Spring Cache 功能,所以一定要添加。代码如下:
// EnableCaching.java
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;

使用缓存带来的问题

高并发下,包括缓存穿透、缓存击穿、缓存雪崩、双写不一致等问题
  • 缓存穿透:大量查询一个null的数据。解决:缓存空数据,配置文件添加配置: cache-null-values: true
  • 缓存雪崩:大量key同时过期。解决:加随机时间;其实只要加上过期时间就可以满足要求 ,配置文件添加配置:time-to-live: 1000
  • 双写不一致:这是一个比较常见的问题,其中一个常用的解决方案是,更新的时候,先删除缓存,再更新数据库。所以Spring Cache的@CacheEvict会有一个beforeInvocation的配置。

 

注解使用注意事项

spring-cache 的注解是基于spring aop代理类, 同一个类中方法A调用方法B, 方法B添加了注解,是不生效的。
//不生效
public void A(String key) {
    // do something...
    //不生效
    this.B();
}

@Cacheable(cacheNames = "myCache")
public void B(String key) {
     // do something...
}

 

标签: Cache Spring Boot Spring Boot Cache
最后更新:2023年10月17日

Akim

犇 骉 Java、C#、Python、Go、Android、MiniProgram、Bootstrap、Vue2

点赞
< 上一篇
下一篇 >
文章目录
  • @Cacheable
  • @CachePut
  • @CacheEvict
  • @Caching
  • @CacheConfig
  • @EnableCaching
  • 使用缓存带来的问题
  • 注解使用注意事项

Copyright © 2025 aianran.com All Rights Reserved.

免责申明 | 隐私政策 | 服务条款 | 关于我们

黔ICP备2023008200号-1

贵公网安备 52010202003594号