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修饰的类,比如String\Integer等会抛出异常
        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

posted @ 2021-01-08 15:05  山兮木  阅读(394)  评论(0编辑  收藏  举报
/* 看板娘 */