Springboot集成Redis详细教程(缓存注解使用@Cacheable,@CacheEvict,@CachePut)

Posted Xd聊架构

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Springboot集成Redis详细教程(缓存注解使用@Cacheable,@CacheEvict,@CachePut)相关的知识,希望对你有一定的参考价值。

文章目录


一、SpringBoot集成Redis

Jedis和Lettuce是Java操作Redis的客户端,在 springboot 1.x版本的默认的Redis客户端是 Jedis实现的,springboot 2.x版本中默认客户端是用 lettuce实现的。
区别如下:

  • Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
  • Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
  • Jedis连接方式最大连接数和最小、最大空闲连接数设置为一样有利于减少上下文切换时间,提升效率。
  • Letturce调大连接池大小反而会影响性能,最佳个数= CPU核数+1,Letturce整体稳定性和性能由于Jedis方式

1.Pom依赖

使用Lettuce客户端:

        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

使用Jedis客户端:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

2.Spring yml文件配置(以Cluster模式为例)

spring:
  redis:
    password: 123456
    cluster:
      nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        max-wait: -1
        min-idle: 0
#redis应用开关,与RedisConfig@ConditionalOnProperty配合使用
cloud:
  redis:
    enabled: true

3.Redis类配置

@EnableCaching
@Configuration
@Slf4j
public class RedisConfig extends CachingConfigurerSupport 

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) 
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = createJackson2JsonRedisSerializer();

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(stringSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    

    @Bean
    /**
     * 当配置cloud.redis.enabled=true时,此配置类/方法才生效,可加在类上,也可加在方法上
     * 建议与spring.cache.type=none一起使用,否则可能无效,猜测Spring本身存在默认CacheManager
     */
    public CacheManager cacheManager(RedisConnectionFactory factory) 
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = createJackson2JsonRedisSerializer();

        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 设置缓存的默认过期时间
                .entryTtl(Duration.ofSeconds(600))
                //cacheable key双冒号变为单冒号
                //.computePrefixWith(name -> ":")
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                // 不缓存空值
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    

    /**
     * redis数据操作异常处理。该方法处理逻辑:在日志中打印出错误信息,但是放行。
     * 保证redis服务器出现连接等问题的时候不影响程序的正常运行
     */
    @Override
    public CacheErrorHandler errorHandler() 
        return new CacheErrorHandler() 
            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache,
                                            Object key, Object value) 
                log.error(exception.getMessage(), exception);
            

            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache,
                                            Object key) 
                log.error(exception.getMessage(), exception);
            

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache,
                                              Object key) 
                log.error(exception.getMessage(), exception);
            

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) 
                log.error(exception.getMessage(), exception);
            
        ;
    

    public Jackson2JsonRedisSerializer createJackson2JsonRedisSerializer()
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 必须配置,否则反序列化得到的是LinkedHashMap对象
        om.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.WRAPPER_ARRAY);
        // 出现未知字段不报错
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        return jackson2JsonRedisSerializer;
    



二、@Cacheable注解使用

Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache(JSR-107)注解简化我们的开发。

其使用方法和原理都类似于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其核心思想是,当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存在缓存中。

1.Cache和CacheManager接口说明

Cache 接口包含缓存的各种操作集合,你操作缓存就是通过这个接口来操作的。
Cache 接口下 Spring 提供了各种 xxxCache 的实现,比如:RedisCache、EhCache、ConcurrentMapCache

CacheManager 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。

2.@Cacheable使用

@Cacheable可以标记在方法和类上面。当标记在方法上表示只对该方法是支持缓存的,当标记在类上面表示该类的所有方法都会支持缓存的,当调用支持注解的方法时会把该方法返回的数据缓存到Redis中,当下次以同样的参数来请求时可以直接从缓存中拿到结果,而不需要执行该方法来拿到数据。Spring Cache是已键值对进行缓存数据的,他的值就是方法的返回结果,他的键Spring又支持两种策略,默认策略和自定义策略

2.1.代码样例

    @Cacheable(value = "test", key = "'dictionary:'+#id", unless = "#result == null")
    public String get(String id) 
        System.out.println("根据id查询数据库数据");
        return "get";
    

下面来了解一下 @Cacheable 的常用属性参数

2.2.@Cacheable常用属性参数

  • cacheNames/value :二者选其一即可,指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式指定多个缓存

  • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写如 #i d;参数id的值 #a0 #p0 #root.args[0])

  • keyGenerator :key的生成器;可以自己指定key的生成器的组件id 然后key 和 keyGenerator 二选一使用

  • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。或者cacheResolver指定获取解析器

  • condition :可以用来指定符合条件的情况下才缓存(condition = “#a0>1”:第一个参数的值>1的时候才进行缓存)

  • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果,unless = “#a0==2”:如果第一个参数的值是2,结果不缓存;)

  • sync :是否使用异步模式。异步模式的情况下unless不支持 默认是方法执行完,以同步的方式将方法返回的结果存在缓存中

2.3.key spEL表达式

3.@CacheEvict使用

用来标注在需要清除缓存元素的方法或类上的

    @CacheEvict(value = "test", key = "'dictionary:'+#id")
    public String delete(String id) 
        System.out.println("根据id删除数据库数据");
        return "delete";
    

allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。

    @CacheEvict(value = "test", allEntries = true)
    public String deleteAll() 
        System.out.println("根据缓存区删除数据库数据");
        return "deleteAll";
    

4.@CachePut使用

不管缓存有没有,都将方法的返回结果写入缓存;适用于缓存更新

    @CachePut(value = "test", key = "'dictionary:'+#id")
    public String saveOrUpdate(String id) 
        System.out.println("根据id保存或修改数据库数据");
        return "saveOrUpdate";
    

5.@Caching使用

@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。


结尾

  • 感谢大家的耐心阅读,如有建议请私信或评论留言。
  • 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步

以上是关于Springboot集成Redis详细教程(缓存注解使用@Cacheable,@CacheEvict,@CachePut)的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot教程(十四) | SpringBoot集成Redis(全网最全)

企业级 SpringBoot 教程 (十三)springboot集成spring cache

企业级 SpringBoot 教程 (十三)springboot集成spring cache

springboot集成redis(缓存篇)

springboot集成redis(缓存篇)

springboot集成redis缓存