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
其他配置
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