SpringBoot 2.x 整合 redis 做缓存,并支持自定义过期时间
2020-06-05 05:56
330 查看
SpringBoot 2.x 整合 redis 做缓存,并支持自定义过期时间
SpringBoot 2.2.0是最新版本,至少在我写这篇文章的此时此刻,为啥用最新版本?因为最新版本的改动相较于2.2.0之前的版本对于redis还是有些改动,所以上新版本之前大伙要注意一下这个问题,我们使用redis接管spring的缓存机制,用于直接使用@Cacheable标记来缓存结果,并随意设定过期时间。
一、redis的相关配置
1、引入spring-redis的依赖
<!-- spring boot redis集成 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- spring boot redis连接池集成 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
2、配置redis数据库
redis: database: 3 host: tst.mindmedia.cn port: 6379 password: M1ndmed1a timeout: 60000 lettuce: #由于Spring Boot2.x 的改动,连接池相关配置需要通过spring.redis.lettuce.pool或者 spring.redis.jedis.pool 进行配置 pool: max-active: 200 #连接池最大连接数(使用负值表示没有限制) 默认8 max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制) min-idle: 0 #连接池中的最小空闲连接 max-idle: 10 #连接池中的最大空闲连接
3、配置CacheManager
/** * redis配置类 * * @author guoyong * @date 0001/2019-11-11 上午 11:48 */ @Configuration @EnableCaching public class RedisCacheConfig extends CachingConfigurerSupport { /** * 默认缓存的过期时间,该过期时间将作用于没有指定过期时间的缓存上 */ private static final Duration timeToLive = Duration.ofHours(1); @Bean(name = "redisTemplate") public RedisTemplate<String, Object redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object template = new RedisTemplate<(); template.setConnectionFactory(redisConnectionFactory); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jdk提供的 template.setValueSerializer(new JdkSerializationRedisSerializer()); // hash的value序列化方式采用jdk提供的 template.setHashValueSerializer(new JdkSerializationRedisSerializer());template.afterPropertiesSet(); return template; } @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisSerializer<String redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer<Object jackson2JsonRedisSerializer = getJackson2JsonRedisSerializer(); // 配置序列化(解决乱码的问题).disableCachingNullValues() 是否允许缓存空值 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .computePrefixWith(keyPrefix()).entryTtl(timeToLive); RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory); return new RedisAutoCacheManager(redisCacheWriter, redisCacheConfiguration); } private Jackson2JsonRedisSerializer<Object getJackson2JsonRedisSerializer() { Jackson2JsonRedisSerializer<Object jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<(Object.class); //解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); return jackson2JsonRedisSerializer; } /** * 缓存前缀(追加一个冒号 : )官方的keyPrefix为给key值末尾追加两个冒号,不知何故,所以这里自定义一下 * * @return */ private CacheKeyPrefix keyPrefix() { return name - name + ":"; } } /** * 重载RedisCacheManager就为了自定义缓存的过期时间 * * @author guoyong * @date 0001/2019-11-11 上午 11:54 */ public class RedisAutoCacheManager extends RedisCacheManager { private static final String SPLIT_FLAG = "#"; private static final int CACHE_LENGTH = 2; public RedisAutoCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter, defaultCacheConfiguration); } @Override protected Collection<RedisCache loadCaches() { return super.loadCaches(); } @Override protected RedisCache getMissingCache(String name) { return super.getMissingCache(name); } @Override public Map<String, RedisCacheConfiguration getCacheConfigurations() { return super.getCacheConfigurations(); } @Override protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { if (StringUtils.isBlank(name) || !name.contains(SPLIT_FLAG)) { return super.createRedisCache(name, cacheConfig); } String[] cacheArray = name.split(SPLIT_FLAG); if (cacheArray.length < CACHE_LENGTH) { return super.createRedisCache(name, cacheConfig); } if (cacheConfig != null) { long cacheAge = Long.parseLong(cacheArray[1]); name = name.substring(0, name.lastIndexOf(SPLIT_FLAG)); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(cacheAge)); } return super.createRedisCache(name, cacheConfig); } @Override public void setTransactionAware(boolean transactionAware) { super.setTransactionAware(transactionAware); } @Override public boolean isTransactionAware() { return super.isTransactionAware(); } @Override protected Cache decorateCache(Cache cache) { return super.decorateCache(cache); } @Override public void afterPropertiesSet() { super.afterPropertiesSet(); } @Override public void initializeCaches() { super.initializeCaches(); } @Override public Cache getCache(String name) { return super.getCache(name); } @Override public Collection<String getCacheNames() { return super.getCacheNames(); } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { return super.equals(obj); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return super.toString(); } @Override protected void finalize() throws Throwable { super.finalize(); } }排版真的一件令人痛苦的事情,从事程序员这个行业这么久,从CSDN上看了无数的文章,今天终于还是忍不住把最近对springboot 2相关的研究发上来跟大家交流,有问题随时找我沟通,在放1个使用示例
/** * 用户信息缓存24小时,redis过期时间为秒 */ private static final String MP_KEY_MEM_APP = "MP:KEY:MEM:APP#" + 24 * 3600; @Autowired private MpMemberMapper mpMemberMapper; @Cacheable(value = MP_KEY_MEM_APP, key = "#mpAppId+':'+#openId") public MpMember getMpMember(String mpAppId, String openId) { MpMember mpMemberSearch = new MpMember(); mpMemberSearch.setMpAppId(mpAppId); mpMemberSearch.setOpenId(openId); log.debug("getMpMember by Db mpAppId {} openId {}", mpAppId, openId); return mpMemberMapper.selectOne(mpMemberSearch); } @CacheEvict(value = MP_KEY_MEM_APP, key = "#mpMember.mpAppId+':'+#mpMember.openId") public int insert(MpMember mpMember) { mpMember.initInsert(); return mpMemberMapper.insert(mpMember); } @CacheEvict(value = MP_KEY_MEM_APP, key = "#mpMember.mpAppId+':'+#mpMember.openId") public int updateByPrimaryKeySelective(MpMember mpMember) { mpMember.initUpdate(); return mpMemberMapper.updateByPrimaryKeySelective(mpMember); }
集成时碰到的问题
// value序列化方式采用jdk提供的 template.setValueSerializer(new JdkSerializationRedisSerializer()); // hash的value序列化方式采用jdk提供的 template.setHashValueSerializer(new JdkSerializationRedisSerializer());
这两个值的序列化方式过变更为Jackson2JsonRedisSerializer的话,使用@Cacheable标记缓存的结果将无法被正常读取出来,会抛解析异常,具体机理我没有仔细研究,有知道的小伙伴欢迎diss我,然后告诉我具体原因
RedisCacheConfiguration.disableCachingNullValues()
是否允许缓存空值,这个值需要特别关注一下,如果启用了,会导致使用@Cacheable缓存标记时会缓存空值,可能会导致非预期的结果,因为有些业务因为时效性的原因是不允许缓存空结果的
相关文章推荐
- Spring Boot Cache + redis 设置有效时间和自动刷新缓存,时间支持在配置文件中配置
- SpringBoot配置Redis自定义过期时间
- spring-boot整合redis作为缓存(3)——自定义key
- spring boot整合reids 然后实现缓存分页(方法之一) 以及RedisTemplate存到reids 里面get 就消失的坑
- spring-boot整合redis作为缓存(4)——spring-boot引入Redis
- Spring Boot 整合 Redis 实现缓存操作
- spring boot整合redis实现缓存机制
- Spring Boot 整合 Redis 实现缓存操作
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- 18.03.24,web学习第八十三天,商城day09,activeMQ和spring整合、详情页加缓存并给过期时间
- 二十三、Spring Boot自定义Redis实现缓存机制
- Spring Boot 整合 Redis 实现缓存操作
- spring-boot | 整合Redis缓存数据
- Spring Boot学习之整合Redis实现缓存
- Spring Boot 整合 Redis 实现缓存操作
- spring-redis-session 自定义 key 和过期时间
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- SpringBoot整合Spring-data-redis实现集中式缓存
- spring-boot整合redis作为缓存(1)——redis的设置
- Spring Boot 整合 Redis 实现缓存操作