redis缓存序列化的泥坑
凡事预则立,不预则废
路过~
最近用springboot和redis过程中,发现一个小问题。问题虽小,但奈何能力不足,用了好久才发现!
1、redis注解序列化不生效
redis序列化有手动序列化和注解序列化,我不打算说这个,我也讲不明白~
网上有很多大神讲解,这里我贴上项目里在用到的序列化的类。
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class MyRedisConfiguration extends CachingConfigurerSupport {
/**
* 使用redisConnectionFactory作为默认序列化方式
* @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);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
//value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//key序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
//hash序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
// 注解模式下序列化问题
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
// 构造config对象,同时设置默认过期时间5min
// 大坑,entryTtl(Duration.ofMinutes(5))要跟在后面,不能写成config.entryTtl(Duration.ofMinutes(5));
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5));
config=config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
return config;
}
}
坑来了!!!
当我们用到注解时,可能会发现Cacheable
可以序列化,但是CachePut
却不能使用我们自定义的序列化。
这里就是容易忽略的点,使用CachePut
的方法需要reture
语句!
因为我们会认为CachePut
方法是用来对数据库进行insert操作的,自然容易漏掉return
//正确写法,有return语句
@CachePut(value = "user01" , key = "'findUser' + '[' + #customer.id + ']'")
public customer addUser(customer customer){
customerMapper.addUser(customer);
return customer; //大坑,CachePut需要返回值,否则无法使用自定义序列化
}
其他:
CachePut
:一般对应update
、inset
Cacheable
:一般对应select
,同样需要return
语句CacheEvict
:一般对应delete
- 自定义序列化类要注意写注解@EnableCaching,增加CacheManager配置
2、自定义序列化过期时间不生效
看一下我们自定义的序列化类的设置过期时间的部分代码
// 注解模式下序列化问题
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
// 关键地方,设置默认过期时间5min
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5));
config=config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
return config;
}
这里如果写成下面的形式则不生效。这是因为entryTtl并不是对当前对象的值的设置,而是会返回一个新的RedisCacheConfiguration对象。所以下面的形式会失效
config.entryTtl(Duration.ofMinutes(5));
不信可以看看RedisCacheConfiguration这个类的entryTtl方法的实现,信的也可以看
public RedisCacheConfiguration entryTtl(Duration ttl) {
Assert.notNull(ttl, "TTL duration must not be null!");
return new RedisCacheConfiguration(ttl, this.cacheNullValues, this.usePrefix, this.keyPrefix, this.keySerializationPair, this.valueSerializationPair, this.conversionService);
}