一.问题描述
错误代码:
package com.xia.redis02springboot;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
@SpringBootTest
class Redis02SpringbootApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
Object sd = redisTemplate.opsForValue().get("money");//获取redis中key为“money"的值。
System.out.println(sd);
}
}
然而结果却是为null,可能是不存在。(强行安慰自己哈哈哈)
就在这时,我去自己的服务器去查询
。。。这就让我迷。为什么idea里面取到的值为null,而在redis客户端上面为什么又能显示?
二. 原因分析
redisTemplate 与StringRedisTemplate 区别
区别主要在于他们使用的序列化类。
- RedisTemplate使用的是 JdkSerializationRedisSerializer
- StringRedisTemplate使用的是 StringRedisSerializer
StringRedisTemplate 继承了RedisTemplate,在构造器中,直接设置了序列化方式
public StringRedisTemplate() {
this.setKeySerializer(RedisSerializer.string());
this.setValueSerializer(RedisSerializer.string());
this.setHashKeySerializer(RedisSerializer.string());
this.setHashValueSerializer(RedisSerializer.string());
}
而使用RedisTemplate使用的序列类在在操作数据的时候,比如说存入数据会将数据先序列化成字节数组。然后在存入Redis数据库,这个时候打开Redis查看的时候,你会看到你的数据不是以可读的形式展现的,而是以字节数组显示
当然从Redis获取数据的时候也会默认将数据当做字节数组转化,当数组是正常形式时
RedisTemplate就无法获取导数据,这个时候获取到的值就是NULL
当Redis当中的数据值是以可读的形式显示出来的时候,只能使用StringRedisTemplate才能获取到里面的数据。所以当你使用RedisTemplate获取不到数据的时候请检查一下是不是Redis里面的数据是可读形式而非字节数组。
用StringRedisTemplate之后:
package com.xia.redis02springboot;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
@SpringBootTest
class Redis02SpringbootApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void contextLoads() {
Object sd = stringRedisTemplate.opsForValue().get("money");
System.out.println(sd);
}
}
这就取到了,嘻嘻。
三.总结
1.redisTemplate只能读取字节数组,不能读取字符串形式的。
2.字符串形式的值,只能使用StringRedisTemplate读取。
四.补充
如果Redistemplate设置了值,在redis客户端却获取不到问题,那该怎么办?
首先,我们要明白一点Redistemplate可以保存所有可序列化的类型,是一个庞大的类,下面就是RedisTemplate类,可以看到俩个泛型K,V
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware
因为Template中set值时会先调用序列化器将键和值都序列化为byte字节数组放入redis数据库中,在客户端除非get后的key值是使用同样的序列化器序列化后的值,否则取不到对应的值。
解决:
自定义Template实现序列化
package com.xia.redis02springboot.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.StringRedisSerializer;
@Configuration
public class RedisConfig{
// 这是我给大家写好的一个固定模板,大家在企业中,拿去就可以直接使用!
// 自己定义了一个 RedisTemplate
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object>redisTemplate(RedisConnectionFactory factory) {
// 我们为了自己开发方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}