为了能提升项目中redis对数据库操作的速度,打算在代码中引入pipeline机制。
原先项目中对于RedisTemplate的定义是
private RedisTemplate redisTemplate;
在configuration中设置的序列化是
@Bean
public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
...
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
...
}
所以原先存取数据的操作是
redisTemplate.opsForValue().set(key, value);
redisTemplate.opsForValue().get(key);
引入pipeline时,发现传入doInRedis的RedisConnection无法直接转换成StringRedisConnection,所以数据的存储只能以byte的形式完成。
redisTemplate.executePipelined(new RedisCallback
自定义类型的value必须转换成byte[],虽然至此存储没有问题了,但是却发现原先代码redisTemplate.opsForValue().get(key);无法将pipeline存入的数据取出来,序列化转换会失败。
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized token 'xxx': was expecting ('true', 'false' or 'null')
那么redisTemplate为什么指定为
首先看一下redisTemplate.opsForValue()的源码
@Override
public ValueOperations opsForValue() {
if (valueOps == null) {
valueOps = new DefaultValueOperations<>(this);
}
return valueOps;
}
发现他默认使用DefaultValueOperations,而DefaultValueOperations在set数据时
public void set(K key, V value) {
byte[] rawValue = rawValue(value);
execute(new ValueDeserializingRedisCallback(key) {
@Override
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
}, true);
}
其实也是将key和value转换成了byte数组类型,但是使用了我们在configuration中设置的Serializer。
byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
if (keySerializer() == null && key instanceof byte[]) {
return (byte[]) key;
}
return keySerializer().serialize(key);
}
byte[] rawValue(Object value) {
if (valueSerializer() == null && value instanceof byte[]) {
return (byte[]) value;
}
return valueSerializer().serialize(value);
}
所以修改pipeline中的代码,使用redisTemplate中已经设置的Serializer重新序列化成byte数据
RedisSerializer keySerializer = redisTemplate.getKeySerializer();
RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
redisTemplate.executePipelined(new RedisCallback
就可以通过redisTemplate.opsForValue().get(key);正常获取pipeline存入的数据了。