zoukankan      html  css  js  c++  java
  • springboot整合redis做缓存操作

    Spring Cache简介

    Spring可以根据@Cacheable 、@CachePut 、@CacheEvict 、@EnableCaching等注解就可以实现对数据的缓存功能。

    添加依赖

    由于SpringBoot 2.x中默认并没有使用Redis连接池,所以需要在pom.xml中添加commons-pool2的依赖;

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

    在application.yml配置文件中,添加redis的配置

    spring:
      redis:
        # Redis服务器地址
        host: 192.168.1.111
        # Redis数据库索引(默认为0)
        database: 0
        # Redis服务器连接端口
        port: 6379
        # Redis服务器连接密码(默认为空)
        password:
        # 连接超时时间
        timeout: 1000ms
        lettuce:
          pool:
            # 连接池最大连接数
            max-active: 8
            # 连接池最大空闲连接数
            max-idle: 8
            # 连接池最小空闲连接数
            min-idle: 0
            # 连接池最大阻塞等待时间,负值表示没有限制
            max-wait: -1ms
    

    添加redisConfig配置类,配置redisTemplate模板

    // 开启redis缓存功能
    @EnableCaching
    // 备注这是一个配置类
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
        /**
         * 配置redis模板文件
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisSerializer<Object> serializer = redisSerializer();
            // 创建RedisTemplate<String, Object>对象
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            // 配置连接工厂
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            // redis key 序列化方式使用stringSerial
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            // redis value 序列化方式使用jackson
            redisTemplate.setValueSerializer(serializer);
            // redis hash key 序列化方式使用stringSerial
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            // redis hash value 序列化方式使用jackson
            redisTemplate.setHashValueSerializer(serializer);
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        /**
         * 配置序列化
         * @return
         */
        @Bean
        public RedisSerializer<Object> redisSerializer() {
            // 定义Jackson2JsonRedisSerializer序列化对象
            Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常
            objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            serializer.setObjectMapper(objectMapper);
            return serializer;
        }
    
        /**
         * 自定义缓存管理器
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
            RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                    .defaultCacheConfig()
                    // 设置value 为自动转json的Object
                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer()))
                    // 缓存有效期为一天
                    .entryTtl(Duration.ofDays(1));
            return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
        }
    
    }
    

    常用注解

    @EnableCaching

    开启缓存功能,一般放在启动类上,也可放在redisConfig配置文件上。

    @Cacheable

    使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。

    一般使用在查询方法上,可以设置如下属性:

    value:缓存名称(必填),指定缓存的命名空间;
    key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义,如果不指定,则缺省按照方法的所有参数进行组合;
    unless:条件符合则不缓存;
    condition:条件符合则缓存。

    执行这个方法的时候,会先去redis中,根据ceshi::user:id(这个id就是前段传来的id)作为key去查找,如果找到直接返回redis中的数据

    如果没有找到就执行该方法,由于unless属性,当返回结果为空就不存入redis中,这里的result是固定写法,指的就是当前返回值User

    当不指定key的时候,就会以方法名作为key,这里就是以id作为key。

    @Cacheable(value = "ceshi", key = "'user:'+#id", unless = "#result==null")
    @GetMapping("{id}")
    public User getUserById(@PathVariable("id") Long id) {
        User user = new User();
        user.setAge(1);
        user.setUserId(10L);
        user.setUsername("张三");
        user.setPassword("123");
        user.setToken("2223334455:333:332");
        return user;
    }
    

    image-20201112191107096

    ceshi::user:id在工具中会以:分隔,所以就会出现图片中的ceshi下一级为空的样子。

    @CachePut

    使用该注解的方法每次执行时都会把返回结果存入缓存中

    一般使用在新增方法上,但是本人觉得新增可以不增加缓存,当查询到这个数据的时候没有再添加缓存即可,可以设置如下属性:

    value:缓存名称(必填),指定缓存的命名空间;
    key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义,如果不指定,则缺省按照方法的所有参数进行组合;
    unless:条件符合则不缓存;
    condition:条件符合则缓存。

    // 更新ceshi 缓存
    @CachePut (value= "ceshi" ,key= "#account.getName()" ) 
    public Account updateAccount(Account account) {
       return updateDB(account);
    }
    

    @CacheEvict

    使用该注解的方法执行时能够根据一定的条件对缓存进行清空。

    一般使用在更新或删除方法上,可以设置如下属性:

    value:缓存名称(必填),指定缓存的命名空间;
    key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
    condition:条件符合则缓存。

    allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

    beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

    // 清空key为ceshi::user:id 的缓存
    @CacheEvict(cacheNames = "ceshi", key = "'user:'+#id")
    @DeleteMapping("{id}")
    public int deleteObject(@PathVariable("id") Long id) {
        return 0;
    }
    
    // 清空ceshi 所有缓存
    @CacheEvict (value= "ceshi" ,allEntries= true ) 
    public void reload() {
        reloadAll()
    }
     
    // 清空ceshi下 userName.length() <=4的缓存
    @Cacheable (value= "ceshi" ,condition= "#userName.length() <=4" ) 
    public Account getAccountByName(String userName) {
      // 方法内部实现不考虑缓存逻辑,直接实现业务
      return getFromDB(userName);
    }
    

    但是以上的做缓存都是粒度比较大的,如果想单独做一些缓存,设置特定的时间什么的,就需要用到以下的工具类

    redis工具类

    /**
     * spring redis 工具类
     **/
    @Component
    public class RedisCache {
        
        @Autowired
        public RedisTemplate redisTemplate;
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key   缓存的键值
         * @param value 缓存的值
         */
        public <T> void setCacheObject(final String key, final T value) {
            redisTemplate.opsForValue().set(key, value);
        }
    
        /**
         * 缓存基本的对象,Integer、String、实体类等
         *
         * @param key      缓存的键值
         * @param value    缓存的值
         * @param timeout  时间
         * @param timeUnit 时间颗粒度
         */
        public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
            redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
        }
    
        /**
         * 设置有效时间
         *
         * @param key     Redis键
         * @param timeout 超时时间
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout) {
            return expire(key, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 设置有效时间
         *
         * @param key     Redis键
         * @param timeout 超时时间
         * @param unit    时间单位
         * @return true=设置成功;false=设置失败
         */
        public boolean expire(final String key, final long timeout, final TimeUnit unit) {
            return redisTemplate.expire(key, timeout, unit);
        }
    
        /**
         * 获得缓存的基本对象。
         *
         * @param key 缓存键值
         * @return 缓存键值对应的数据
         */
        public <T> T getCacheObject(final String key) {
            ValueOperations<String, T> operation = redisTemplate.opsForValue();
            return operation.get(key);
        }
    
        /**
         * 删除单个对象
         *
         * @param key
         */
        public boolean deleteObject(final String key) {
            return redisTemplate.delete(key);
        }
    
        /**
         * 删除集合对象
         *
         * @param collection 多个对象
         * @return
         */
        public long deleteObject(final Collection collection) {
            return redisTemplate.delete(collection);
        }
    
        /**
         * 缓存List数据
         *
         * @param key    缓存的键值
         * @param values 待缓存的List数据
         * @return 缓存的对象
         */
        public <T> long setCacheList(final String key, final List<T> dataList) {
            Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
            return count == null ? 0 : count;
        }
    
        /**
         * 获得缓存的list对象
         *
         * @param key 缓存的键值
         * @return 缓存键值对应的数据
         */
        public <T> List<T> getCacheList(final String key) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        /**
         * 缓存Set
         *
         * @param key     缓存键值
         * @param dataSet 缓存的数据
         * @return 缓存数据的对象
         */
        public <T> long setCacheSet(final String key, final Set<T> dataSet) {
            Long count = redisTemplate.opsForSet().add(key, dataSet);
            return count == null ? 0 : count;
        }
    
        /**
         * 获得缓存的set
         *
         * @param key
         * @return
         */
        public <T> Set<T> getCacheSet(final String key) {
            return redisTemplate.opsForSet().members(key);
        }
    
        /**
         * 缓存Map
         *
         * @param key
         * @param dataMap
         */
        public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
            if (dataMap != null) {
                redisTemplate.opsForHash().putAll(key, dataMap);
            }
        }
    
        /**
         * 获得缓存的Map
         *
         * @param key
         * @return
         */
        public <T> Map<String, T> getCacheMap(final String key) {
            return redisTemplate.opsForHash().entries(key);
        }
    
        /**
         * 往Hash中存入数据
         *
         * @param key   Redis键
         * @param hKey  Hash键
         * @param value 值
         */
        public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
            redisTemplate.opsForHash().put(key, hKey, value);
        }
    
        /**
         * 获取Hash中的数据
         *
         * @param key  Redis键
         * @param hKey Hash键
         * @return Hash中的对象
         */
        public <T> T getCacheMapValue(final String key, final String hKey) {
            HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
            return opsForHash.get(key, hKey);
        }
    
        /**
         * 获取多个Hash中的数据
         *
         * @param key   Redis键
         * @param hKeys Hash键集合
         * @return Hash对象集合
         */
        public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
            return redisTemplate.opsForHash().multiGet(key, hKeys);
        }
    
        /**
         * 获得缓存的基本对象列表
         *
         * @param pattern 字符串前缀
         * @return 对象列表
         */
        public Collection<String> keys(final String pattern) {
            return redisTemplate.keys(pattern);
        }
        
    }
    

    参考:http://www.macrozheng.com/#/reference/spring_data_redis

    http://www.ruoyi.vip/

  • 相关阅读:
    解决“google快照无法打开”的简单而有效的方法~
    在Struts2里面嵌入Spring
    HDU
    设计模式大总结(二)
    Node.js入门笔记
    草图检索和识别[开源]
    2019-10-31-VisualStudio-断点调试详解
    2019-10-31-VisualStudio-断点调试详解
    2019-9-2-C#-设计模式-责任链
    2019-9-2-C#-设计模式-责任链
  • 原文地址:https://www.cnblogs.com/sun2020/p/re.html
Copyright © 2011-2022 走看看