缓存注解@Cacheable、@CacheEvict、@CachePutSpringBoo。。。
@Cacheable、@CacheEvict、@CachePut为Spring⾃带缓存,可作⽤在⽅法和类上。作⽤在⽅法上时,只对⽅法⽣效,作⽤在类上时,对类中所有⽅法⽣效。
没有集成Redis时,默认缓存为内存。集成Redis后,缓存内容将存⼊Redis。
SpringBoot项⽬在pom中引⼊Redis包并在application配置⽂件中配置后。在启动类上加上@EnableCaching注解 ⾃动⽣效,缓存存⼊Redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
application.properties
#dis.password=123456
# 连接超时时间单位 ms(毫秒)
#=========redis线程池设置=========
# 连接池中的最⼤空闲连接,默认值也是8。
#连接池中的最⼩空闲连接,默认值也是0。
# 如果赋值为-1,则表⽰不限制;pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
# 等待可⽤连接的最⼤时间,单位毫秒,默认值为-1,表⽰永不超时
此时我们连续调⽤三次下⾯接⼝
@RequestMapping("/b")
@Cacheable(value ="cache",key ="#id")
public List<String>getPrud(@RequestParam("id") String id){
System.out.println("进⼊⽅法");
List<String> list =new ArrayList<>();
list.add(id);
list.add("123");
list.add("456");
return list;
}
发现三次都返回正确结果,但是查看控制台发现只执⾏了⼀次接⼝
这就是因为缓存起到作⽤了,后⾯两次发现缓存中有值,直接返回缓存中的结果,不执⾏⽅法。
去Redis中查看
发现的确有缓存,但是是乱码。进⾏如下配置,解决乱码问题
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private Duration timeToLive = Duration.ofHours(1);
@Bean
public RedisTemplate<Object, Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> redisTemplate =new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使⽤Jackson2JsonRedisSerialize 替换默认序列化
el表达式执行结果为Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper =new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisSerializer<String> redisSerializer =new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om =new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(timeToLive)
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
问题解决
下⾯详细说说⼏个注解的作⽤
@Cacheable
调⽤⽅法前先去缓存中根据key查是否有缓存,如果有则直接返回缓存结果,不调⽤⽅法;如果没有到则执⾏⽅法,并在将⽅法返回值存⼊缓存中。
@Cacheable(value = “cache”,key = “#id”) 为例
其中value表⽰缓存名称,为必填。表⽰当前⽅法的返回值会被缓存在哪个Cache上,可以是⼀个Cache也可以是多个Cache,当需要指定多个Cache时其是⼀个数组。
key表⽰缓存的key,有⾃动⽣成策略和⾃定义两种。上⾯的写法是Spring的EL表达式,最后缓存的key的值就是⽅法接受参数id的值。
//若user.id=1 key值为 users::user1
@Cacheable(value="users", key="'user'+#user.id")
public User find(User user){
return null;
}
condition
@RequestMapping("/b")
@Cacheable(value ="cache",key ="#id",condition="#id%2 == 0")
public List<String>getPrud(@RequestParam("id") String id){
System.out.println("进⼊⽅法");
List<String> list =new ArrayList<>();
list.add(id);
list.add("123");
list.add("456");
return list;
}
表⽰表达式 id%2 == 0 为true时才会将⽅法返回结果进⾏缓存。
unless
和condition⼀个作⽤,以表达式结果判断是否进⾏缓存
既然 condition 和 unless 都能决定是否进⾏缓存,那么同时指定这两个参数并且结果相冲突的时候,会怎么样呢?
condition 不指定相当于 true,unless 不指定相当于 false
当 condition = false,⼀定不会缓存;
当 condition = true,且 unless = true,不缓存;
当 condition = true,且 unless = false,缓存;
@CachePut
@CachePut标注的⽅法在执⾏前不会去检查缓存中是否存在之前执⾏过的结果,⽽是每次都会执⾏该⽅法,并将执⾏结果以键值对的形式存⼊指定的缓存中。
@CacheEvict
@CacheEvict表⽰在⽅法执⾏完成之后,默认执⾏清除缓存操作。
@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表⽰清除操作是发⽣在哪些Cache上的(对应Cache的名称);key表⽰需要清除的是哪个key,如未指定则会使⽤默认策略⽣成的key;condition表⽰清除操作发⽣的条件。下⾯我们来介绍⼀下新出现的两个属性allEntries和beforeInvocation。
**allEntries**是boolean类型,表⽰是否需要清除缓存中的所有元素。默认为false,表⽰不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache⼀下清除所有的元素,这⽐⼀个⼀个清除元素更有效率。
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id){
System.out.println("delete user by id: "+ id);
}
**beforeInvocation** 清除操作默认是在对应⽅法成功执⾏之后触发的,即⽅法如果因为抛出异常⽽未能成功返回时也不会触发清除操作。使⽤beforeInvocation 可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调⽤该⽅法之前清除缓存中的指定元素。
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id){
System.out.println("delete user by id: "+ id);
}
@Caching
⽤于组合@Cacheable、@CacheEvict、@CachePut 三个注解
@Caching(
@CacheEvict(value={"SubscribeRecordPO_LIST"}, key ="'orgCode'+#po.getTargetOrgCode()"),
@CachePut(value={"SubscribeRecordPO"}, key ="'macCode'+#po.getMacCode()",unless ="#result =
= null")
)
public SubscribeRecordPO updateSubscribe(SubscribeRecordPO po){
//TODO
}
上⾯的代码表⽰在⽅法执⾏后清除缓存SubscribeRecordPO_LIST中key值为"‘orgCode’+#po.getTargetOrgCode()"的缓存,在⽅法执⾏后且返回值不为null时,将返回值缓存进SubscribeRecordPO中。
参考
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论