选择默认缓存器中间件
springboot集成redis,配置redis为默认缓存器
引入依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
方式一:
设置默认超时时间1小时 针对所有注解缓存
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
/* 默认配置, 默认超时时间为1小时 */
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration
.ofHours(1)).disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter
(connectionFactory)).cacheDefaults(defaultCacheConfig).transactionAware().build();
return cacheManager;
}
}
方式二:
对每个缓存空间应用不同的配置
默认超时时间10分钟 针对areaCodes的缓存空间超时时间为60秒 pangolin默认时间为30秒
缓存空间配合@Cacheable(value = "areaCodes")注解中value值使用
@Configuration
@EnableCaching
public class CacheConfig {
@Autowired
RedisConnectionFactory connectionFactory;
@Bean
CacheManager cacheManager() {
/* 默认配置, 默认超时时间为10分钟 */
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration
.ofMinutes(10)).disableCachingNullValues();
Set<String> cacheNames = new HashSet<>();
cacheNames.add("areaCodes");
cacheNames.add("pangolin");
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("areaCodes", defaultCacheConfig.entryTtl(Duration.ofSeconds(60)));
//这个缓存空间30秒
configMap.put("pangolin", defaultCacheConfig.entryTtl(Duration.ofSeconds(30)));
RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter
(connectionFactory))
.cacheDefaults(defaultCacheConfig)
// 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
return cacheManager;
}
}
@EnableCaching 注解加入到配置类或者启动类上都可以
@Cacheable
测试代码
controller
@GetMapping("/getAreaCodeFromRedisBatch")
@ApiOperation(value = "redis获取areacode批量",notes = "redis获取areacode批量")
public ResponseEntity<List<AreaCode>> getAreaCodeFromRedisBatch(){
List<AreaCode> areaCodeList = redisService.queryAreaCodes();
return ResponseEntity.ok().body(areaCodeList);
}
service
@Cacheable(value = "areaCodes", key = "'pangolin'", unless = "#result==null")
public List<AreaCode> queryAreaCodes(){
List<AreaCode> all = areaCodeRepository.findAll();
return all;
}
redis缓存结构图
根据key 获取过期时间
Long areaCodes = redisTemplate.getExpire("areaCodes::pangolin:areaCode:all", TimeUnit.SECONDS);
此时返回过期时间为实时过期时间 -1为无过期时间 -2为未找到key信息
如果缓存配置使用方式二 则areaCodes缓存空间数据超时时间为60秒
value属性指定Cache名称
value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
@Cacheable("cache1")//Cache是发生在cache1上的
public User find(Integer id) {
returnnull;
}
@Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
public User find(Integer id) {
returnnull;
}
使用key属性自定义key
key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。
key的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。
当key使用”#参数名”时 对应的方法参数不能为空。
@Cacheable(value = "hour", key = "#id")
public String selectById(Serializable id) {
Long timestamp = System.currentTimeMillis();
return timestamp.toString();
}
否则会报错
java.lang.IllegalArgumentException: Null key returned for cache operation (maybe you are using named params on classes without debug info?) Builder[public java.util.List com.example.demo.service.RedisService.queryAreaCodes()] caches=[areaCodes] | key='#pangolin' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='#result==null' | sync='false'
condition属性指定发生的条件
有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当user的id为偶数时才会进行缓存。
@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排除特定返回值
unless参数的作用是:函数返回值符合表达式条件的不缓存
换句话说,函数返回值符合条件的排除掉、只缓存其余不符合条件
注解的condition和unless的区别,condition对传入值生效,unless对结果result生效,使用了错误的result导致报空错误
测试结果
首次执行查询时 redis缓存库中无所对应的key值,将查询结果缓存到redis生成对应的key 值。
再次执行查询方法,在方法执行前会去缓存找到对应key的值返回结果,不会执行jpa去查询。
@CachePut
@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
@CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
- allEntries属性
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。
- beforeInvocation属性
清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。
注意:当使用 redisTemplate去设置key 数据时没有显式的设置超时时间,则默认为没有超时时间 即永久数据
配置类的超时时间不针对redisTemplate适用
stringObjectRedisTemplate.opsForValue().set("keys:areaCode",keys,30,TimeUnit.SECONDS);