zoukankan      html  css  js  c++  java
  • SpringBoot---缓存技术2(基于Redis注解和基于RedisTemplate的手动缓存,包括将缓存数据序列化成json数据,有源码)

    基于注解的Redis缓存实现

    1、加入redis依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    其他依赖

    复制代码
    <!--a阿里数据druid数据源-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.14</version>
            </dependency>
    <!--针对mybatis实体类的注解-->
            <dependency>
                <groupId>javax.persistence</groupId>
                <artifactId>persistence-api</artifactId>
                <version>1.0</version>
            </dependency>
    <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
    <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
    复制代码

    2、在配置文件中添加redis配置

    复制代码
      #redis配置
      redis:
        host: 192.168.56.1
        port: 6379
        password:
    
    # spirng 缓存管理参数配置
      cache:
        redis:
          time-to-live: 500000
    复制代码

    其他配置

     application.yml

    3、在项目启动类中上添加@EnableCaching注解,表明启用缓存功能。

    @SpringBootApplication
    @EnableCaching
    public class Ch06CacheApplication {
        public static void main(String[] args) {     
         SpringApplication.run(Ch06CacheApplication.class, args);}}

    4、在CommentServiceImpl中使用缓存注解

    • @CacheConfig(cacheNames="comment")    ---为缓存配置名字
    • @Cacheable(key="#id")         ---查询
    • @CachePut(key="#result.id")         ---修改
    • @CacheEvict                ---删除
    复制代码
    @Service
    @Transactional
    @CacheConfig(cacheNames = "comment")
    public class CommentServiceImpl implements CommentService{
    
        @Autowired
        private CommentMapper commentMapper;
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Cacheable(key = "#id")
        @Override
        public Comment get(long id) {
            Object o = redisTemplate.opsForValue().get("comment_" + id);
            if (o != null) {
                return (Comment) o;
            } else {
                Comment comment = commentMapper.get(id);
                if (comment != null) {
                    redisTemplate.opsForValue().set("comment_" + id, comment);
                }
                    return comment;
            }
        }
    
        @CachePut(key = "#result.id")
        @Override
        public Comment update (Comment comment){
            int result = commentMapper.update(comment);
            if (result == 1) {
                redisTemplate.opsForValue().set("comment_" + comment.getId(), comment);
            }
            return comment;
        }
    
        @Override
       @CacheEvict public int delete ( long id){ int result = commentMapper.delete(id); if (result == 1) { redisTemplate.delete("comment_" + id); } return result; } }
    复制代码

    5、启动Redis服务器。

     6、启动项目,选Tools -> HTTP Client -> Test RESTful Web Service,使用idea提供的HTTP客户端测试查询id为1的comment。

     点击绿色三角执行查询。当看到如下图查询出了对应数据表示,表明到数据库的查询没有异常。

     此时,打开Redis Desktop Manager可以查看到数据,表明上面的数据已缓存到Redis中。

    修改基于注解的序列化方式

    上面,我们实现了基于注解的Redis缓存实现,但是存在的问题是缓存的数据可视化程度很低,我们可以将默认的序列化方式改为序列化为json提高可视化程度。

    1、在config文件夹中新建一个RedisConfig类,这是一个配置类需要加上@Configuration注解。

    2、在RedisConfig类中配置RedisCacheManager,将默认的JdkSerializationRedisSerializer替换为Jackson2JsonRedisSerializer

    复制代码
    /**
     * 自定义Redis配置类,进行序列化以及RedisTemplate设置
     */
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
        @Value("${spring.cache.redis.time-to-live}")
        private Duration timeToLive = Duration.ZERO;
    //    定义cacheManager,统一redis的属性配置
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
    
            //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper objectMapper=new ObjectMapper();
            //指定要序列化的域,field,get和set,以及修饰范围,ANY是都有包括private和public
            objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
    
            //此项必须配置,否则会报Java.lang.ClassCastException:java.util.LinkedHashMap cannot be cast to XXX
            //指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如StringInteger等会抛出异常
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            RedisSerializer<String> redisSerializer = new StringRedisSerializer();
            // 配置序列化(解决乱码的问题)
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                    // 缓存有效期
                    .entryTtl(timeToLive)
                    // 使用StringRedisSerializer来序列化和反序列化redis的key值
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                    // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                    // 禁用空值
                    .disableCachingNullValues();
    
              RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
              return cacheManager;
        }
    
        /**
         * 配置Jackson2JsonRedisSerializer序列化策略
         * */
        private Jackson2JsonRedisSerializer<Object> jackson2Serializer() {
            // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            return jackson2JsonRedisSerializer;
        }
    }
    复制代码

    3、重新启动项目,再执行一遍part1中的查询,用Redis Desktop Manager查看数据,可以看到,数据的格式已转换为json格式。

    基于自定义RedisTemplate的缓存实现

    1、在ArticleServiceImpl,我们注入RedisTemplate,手动完成数据的查询和缓存

    复制代码
    @Service
    @Transactional
    @CacheConfig(cacheNames = "default")
    public class ArticleServiceImpl implements ArticleService{
    
        @Autowired
        ArticleMapper articleMapper;
        @Autowired
        RedisTemplate redisTemplate;
    
        @Override
        public Article get(long id) {
            Object object=redisTemplate.opsForValue().get("article_"+id);
            if(object !=null){
                return (Article) object;
            }else{
                Article article=articleMapper.get(id);
                if(article !=null)
                    redisTemplate.opsForValue().set("article_"+id,article,100,TimeUnit.SECONDS);
                return article;
            }
        }
    
        @Override
        public int delete(long id) {
            int result=articleMapper.delete(id);
            if(result==1){
                redisTemplate.delete("article_"+id);
            }
            return result;
        }
    
        @Override
        public Article update(Article article) {
            int result=articleMapper.update(article);
            if(result==1){
                redisTemplate.opsForValue().set("article_"+article.getId(),article);
            }
            return article;
        }
    }
    复制代码

    2、使用HTTP Client测试缓存是否成功。

     能显示数据表明查询成功,此时通过Redis客户端可以查询到缓存的数据,表明缓存成功。

     3、修改基于RedisTemplate的序列化方式(同样,我们也可以将RedisTemplate的默认序列化方式改为json序列化。)

    在RedisConfig配置类中添加以下代码,替换序列化方式:

    复制代码
    /**
     * 自定义Redis配置类,进行序列化以及RedisTemplate设置
     */
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
        @Value("${spring.cache.redis.time-to-live}")
        private Duration timeToLive = Duration.ZERO;
        /**
         *  定制Redis API模板RedisTemplate
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> template = new RedisTemplate();
            template.setConnectionFactory(redisConnectionFactory);
            //使用jackson序列化
            // 使用JSON格式序列化对象,对缓存数据key和value进行转换
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询时候的转换异常问题
            ObjectMapper objectMapper=new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
            // 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            // 设置RedisTemplate模板API的序列化方式为JSON
            template.setDefaultSerializer(jackson2JsonRedisSerializer);
            return template;
        }
     /**
         * 配置Jackson2JsonRedisSerializer序列化策略
         * */
        private Jackson2JsonRedisSerializer<Object> jackson2Serializer() {
            // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            return jackson2JsonRedisSerializer;
        }
    }
    复制代码

    4、重新启动项目, 使用HTTP Client查询article数据,再查看Redis,可以发现缓存的article数据已变为json格式。

     数据库文件:

    链接:https://pan.baidu.com/s/1EZp04DNSjcdzeGSqtnnzTg
    提取码:qwhj

    源码:

    链接:https://pan.baidu.com/s/12Q2JjlCiChgSzTtqOkb3ZQ
    提取码:eo7w

     注解添加 过期时间  : https://www.it610.com/article/1294646751977873408.htm    https://zhuanlan.zhihu.com/p/338718644

     redis与localdatetime序列化问题 https://blog.csdn.net/weixin_43741902/article/details/107790807

    转载地址:https://www.cnblogs.com/technicist/p/13639370.html

  • 相关阅读:
    导出PDF乱码
    C/S模式下的打印方法
    填报表导出excel后不可写的单元格处于锁定状态
    多表批量导出txt及打压缩包下载
    客户端定时自动打印页面的例子
    套打中的自定义纸张设置
    linux客户端打印报表时操作系统的配置
    大数据量报表APPLET打印分页传输方案
    Python中类的定义及使用
    Solr7.7高级应用【MLT相似文档搜索、自动补全、自动纠错】
  • 原文地址:https://www.cnblogs.com/xr210/p/14251486.html
Copyright © 2011-2022 走看看