zoukankan      html  css  js  c++  java
  • 【测试开发】知识点项目中使用 Spring Cache + Redis 缓存数据

    有时候我们为了提高查询速度,会使用缓存,但是并不是所有数据都适合放到缓存中来。

    像一些不经常修改的数据、固定的数据、经常查询的数据等,是适合放到缓存的。

    那么现在就把之前实现的字典功能里的数据,放到缓存里去。

    一、Spring Cache + Redis 介绍

    Spring Cache是一个非常优秀的缓存组件。

    自 Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)。

    使用Spring Cache的优点:

    • 提供基本的Cache抽象,方便切换各种底层Cache
    • 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成
    • 提供事务回滚时也自动回滚缓存
    • 支持比较复杂的缓存逻辑

    二、项目中集成

    1. 引入依赖

        <dependencies>
            <!-- redis -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    
            <!-- spring2.X集成redis所需common-pool2-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>2.6.0</version>
            </dependency>
    
        </dependencies>
    

    2. 添加 redis 配置类

    配置类是一个比较固定的写法,需要了解下结构。

    // 配置类
    @Configuration
    // 开启缓存处理
    @EnableCaching
    public class RedisConfig {
    
        /**
         * 自定义key规则
         *
         * @return
         */
        @Bean
        public KeyGenerator keyGenerator() {
            return new KeyGenerator() {
                @Override
                public Object generate(Object target, Method method, Object... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(target.getClass().getName());
                    sb.append(method.getName());
                    for (Object obj : params) {
                        sb.append(obj.toString());
                    }
                    return sb.toString();
                }
            };
        }
    
        /**
         * 设置RedisTemplate规则
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            //序列号key value
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        /**
         * 设置CacheManager缓存规则
         * @param factory
         * @return
         */
        @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);
    
            // 配置序列化(解决乱码的问题),过期时间600秒
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofSeconds(600))
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                    .disableCachingNullValues();
    
            RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                    .cacheDefaults(config)
                    .build();
            return cacheManager;
        }
    }
    

    主要是 3 个方法:

    • 自定义key规则:可以更具我们自定义规则生成 key。
    • 设置RedisTemplate规则:后续操作redis,往里存取内容,需要用到 RedisTemplate,这里进行相关设置。
    • 设置CacheManager缓存规则:处理缓存相关的一些规则,比如缓存时间、乱码处理等。

    3. 配置文件增加 redis 配置

    spring.redis.host=XXX.XXX.XXX.XX
    spring.redis.port=6379
    spring.redis.database= 0
    spring.redis.timeout=1800000
    
    spring.redis.lettuce.pool.max-active=20
    spring.redis.lettuce.pool.max-wait=-1
    #最大阻塞等待时间(负数表示没限制)
    spring.redis.lettuce.pool.max-idle=5
    spring.redis.lettuce.pool.min-idle=0
    

    4. 启动安装好的 redis

    安装相关可以参考我之前的分享:

    https://www.cnblogs.com/pingguo-softwaretesting/p/14883012.html

    我换了台云服务器,也重新安装了下,测试正常。

    这是单机操作,如果需要其他主机也可以链接到redis,还要改个配置:

    三、Spring Cache 常用注解介绍

    Spring Cache 提供了相关注解,可以让我们很方便实现缓存操作,先看下最常用的几个。

    1. @Cacheable

    用的最多的注解,功能也很强大,一般用在查询方法上。

    可以根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。

    说白了,比如我第一次查询缓存操作,如果不存在就去查询数据库,查到数据后返回,并且放到缓存里去,当第二次查询的时候就可以查询缓存里的数据。

    查看源码,属性值如下:

    • value:缓存名,必填,它指定了你的缓存存放在哪块命名空间
    • cacheNames:与 value 差不多,二选一即可
    • key:可选属性,可以使用 SpEL 标签自定义缓存的key

    2. @CachePut

    一般用在新增方法上。

    使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。

    查看源码,属性值如下:

    • value:缓存名,必填,它指定了你的缓存存放在哪块命名空间
    • cacheNames:与 value 差不多,二选一即可
    • key:可选属性,可以使用 SpEL 标签自定义缓存的key

    3. @CacheEvict

    一般用在更新或者删除方法上,使用该注解标志的方法,会清空指定的缓存。

    查看源码,属性值如下:

    • value:缓存名,必填,它指定了你的缓存存放在哪块命名空间
    • cacheNames:与 value 差不多,二选一即可
    • key:可选属性,可以使用 SpEL 标签自定义缓存的key
    • allEntries:是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
    • beforeInvocation:是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

    四、功能里实现缓存操作

    改造之前的字典功能,加入缓存相关操作,在查询和导入(新增)的操作上增加对应注解。

    查询操作

    在 service 层对应的实现方法上增加注解@Cacheable(value = "dict", keyGenerator = "keyGenerator")

    value = "dict", keyGenerator = "keyGenerator",这里面传入的值就是为了构造key,keyGenerator就是redis配置类里定义的:

    接下来到前端刷新一下列表页面,进行一次查询请求,然后查看下redis:

    这个 key 就是按照配置类里自定义的规则构建出来的,再来查询一下这个 key:

    缓存里有数据了。

    导入操作

    在 service 层对应的实现方法上增加注解@CacheEvict(value = "dict", allEntries=true)

    测试一下,我先del删除掉缓存,然后前端页面做一个导入的操作:

    导入成功后,再次查看缓存:

    新增成功。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    蓝桥网试题 java 基础练习 特殊的数字
    蓝桥网试题 java 基础练习 杨辉三角形
    蓝桥网试题 java 基础练习 查找整数
    蓝桥网试题 java 基础练习 数列特征
    蓝桥网试题 java 基础练习 字母图形
    蓝桥网试题 java 基础练习 01字串
    蓝桥网试题 java 基础练习 回文数
    蓝桥网试题 java 基础练习 特殊回文数
    Using text search in Web page with Sikuli
    each of which 用法
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15706680.html
Copyright © 2011-2022 走看看