RedisTemplate序列化StringRedisSerializer只能支持String的坑

  • 项目使用了spring-data-redis包的RedisTemplate类进行redis操作,在配置value的序列化类使用了StringRedisSerializer,如下:
private RedisTemplate<String, Object> buildRedisTemplate(JedisConnectionFactory connectionFactory) {
       RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(new StringRedisSerializer());
       redisTemplate.setHashKeySerializer(new StringRedisSerializer());
       redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
       redisTemplate.setConnectionFactory(connectionFactory);
       return redisTemplate;
   }

redisTemplate.setValueSerializer(new StringRedisSerializer());

  • StringRedisSerializer只能存储类型为String的value,当存储其他类型的数据,如double,则无法将value保存到redis,必须转为String。
Double value = 12.0;
BoundValueOperations<String, Object> valOps = redisTemplate.boundValueOps(key);
valOps.set(value);

Double value = 12.0;
BoundValueOperations<String, Object> valOps = redisTemplate.boundValueOps(key);
valOps.set(value.toString());

StringRedisSerializer源码如下:大概意思只能在String和byte[]之间序列化和反序列化。

/**
 * Simple String to byte[] (and back) serializer. Converts Strings into bytes and vice-versa using the specified charset
 * (by default UTF-8).
 * <p>
 * Useful when the interaction with the Redis happens mainly through Strings.
 * <p>
 * Does not perform any null conversion since empty strings are valid keys/values.
 * 
 * @author Costin Leau
 */
public class StringRedisSerializer implements RedisSerializer<String> {

	private final Charset charset;

	public StringRedisSerializer() {
		this(Charset.forName("UTF8"));
	}

	public StringRedisSerializer(Charset charset) {
		Assert.notNull(charset);
		this.charset = charset;
	}

	public String deserialize(byte[] bytes) {
		return (bytes == null ? null : new String(bytes, charset));
	}

	public byte[] serialize(String string) {
		return (string == null ? null : string.getBytes(charset));
	}
}
  • 故需要改成Jackson2JsonRedisSerializer,才能存储Double类型的数据。如下:
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

但是马上报错了:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized token 'NIO': was expecting 'null', 'true', 'false' or NaN
 at [Source: [B@6bb7cce7; line: 1, column: 7]; nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'NIO': was expecting 'null', 'true', 'false' or NaN
 at [Source: [B@6bb7cce7; line: 1, column: 7]
	at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:73)
	at org.springframework.data.redis.serializer.SerializationUtils.deserializeValues(SerializationUtils.java:50)
	at org.springframework.data.redis.serializer.SerializationUtils.deserialize(SerializationUtils.java:58)
	at org.springframework.data.redis.core.AbstractOperations.deserializeValues(AbstractOperations.java:202)
	at org.springframework.data.redis.core.DefaultSetOperations.members(DefaultSetOperations.java:134)
	at org.springframework.data.redis.core.DefaultBoundSetOperations.members(DefaultBoundSetOperations.java:91)

异常大概的意思:换成后无法将之前序列化保存的数据反序列化出来了。具体为如下调用members获取set的数据时,无法反序列化出来,坑就在这里,

写入set:
BoundSetOperations<String, Object> setOps = redisTemplate.boundSetOps(key);
setOps.add(symbol);
读出set:
BoundSetOperations<String, Object> setOps = redisTemplate.boundSetOps(key);
return setOps.members();

故在设计之初要使用:

redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

才能支持多种数据类型的存储,避免存储了一些数据之后再来换,就需要对历史数据进行处理了,否则无法进行反序列化。
Jackson2JsonRedisSerializer的源码:使用FastJSON来进行序列化和反序列化。

/**
 * {@link RedisSerializer} that can read and write JSON using <a
 * href="https://github.com/FasterXML/jackson-core">Jackson's</a> and <a
 * href="https://github.com/FasterXML/jackson-databind">Jackson Databind</a> {@link ObjectMapper}.
 * <p>
 * This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances.
 * <b>Note:</b>Null objects are serialized as empty arrays and vice versa.
 * 
 * @author Thomas Darimont
 * @since 1.2
 */
public class Jackson2JsonRedisSerializer<T> implements RedisSerializer<T> {

	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

	private final JavaType javaType;

	private ObjectMapper objectMapper = new ObjectMapper();
	...
}

推荐阅读:
https://blog.csdn.net/jinzhencs/article/details/75123631
https://stackoverflow.com/questions/46233296/can-not-store-non-string-object-when-using-stringredisserializer-for-hashvaluese

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值