缓存注解@Cacheable、@CacheEvict、@CachePut && SpringBoot && Redis

@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

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=5
#spring.redis.password=123456
# 连接超时时间 单位 ms(毫秒)
spring.redis.timeout=3000
#=========redis线程池设置=========
# 连接池中的最大空闲连接,默认值也是8。
spring.redis.pool.max-idle=10
#连接池中的最小空闲连接,默认值也是0。
spring.redis.pool.min-idle=0
# 如果赋值为-1,则表示不限制;pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
spring.redis.pool.max-active=10
# 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时
spring.redis.pool.max-wait=1000

此时我们连续调用三次下面接口

@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 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        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);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        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中。

参考
@Cacheable缓存注解(以Redis作为缓存)
SpringBoot Redis缓存 @Cacheable、@CacheEvict、@CachePut

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值