前置:本文基于springboot 2.1.6.RELEASE,redis版本为5.0.4
大家平时使用springdata-redis时,主要用到两个类:RedisTemplate和StringRedisTemplate。使用这两个类来存储字符串或者对象时,大家有使用redis客户端来查看过存储的格式吗?
RedisTemplate
简单的示例
存入一个简单字符串。
redisTemplate.opsForValue().set("name","zs");
使用redis客户端查看
发现key已经不是一个简单的字符串了。可想,那么value肯定也不是一个简单的字符串了。
如果存入一个对象呀(此处的User类需要实现Serializable接口,后面会解释为什么)。
User user = new User();
user.setUsername("张三");
user.setPassword("123");
user.setAge(20);
redisTemplate.opsForValue().set("user",user);
可见key和value都被安装一定的格式处理过了,然后才存储到redis中。
查看原因
打开RedisAutoConfiguration查看
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
并没发现什么有用的信息。
那么继续查询RedisTemplate的源码
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
// 发现这里redisTemplate设置了默认的序列化格式
if (defaultSerializer == null) {
// 默认使用的JdkSerializationRedisSerializer
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
// 默认为true
if (enableDefaultSerializer) {
if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
}
if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
}
if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<>(this);
}
initialized = true;
}
在源码中发现使用了JdkSerializationRedisSerializer类来序列化。
RedisSerializer
通过查询继承关系,发现JdkSerializationRedisSerializer实现了RedisSerializer接口
结论:如果使用RedisTemplate,默认情况下 key、value、hashkey、hashvalue都是使用的jdk的Serializable方式序列化。所以我们如果要存对象,那么必须要实现Serializable接口。
那么我就想使用RedisTemplate,但是还想使用json方式存储,那么我们就要自己去定义RedisTemplate的bean,而不是用springboot自动配置的。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 设置默认的序列化方式为json
template.setDefaultSerializer(RedisSerializer.json());
return template;
}
}
那么再存对象
@Test
public void testRedisSet(){
User user = new User();
user.setUsername("张三");
user.setPassword("123");
user.setAge(20);
redisTemplate.opsForValue().set("user",user);
}
结果已经变为了json
注意:classpath中一定要有Jackson,如果使用springboot则不用担心,因为已经传递依赖了,并且springboot还自动配置了Jackson。
如果大家使用不是Jackson,而是fastjson,那么大家可以下去研究一下怎么配置哦。(提示:需要定义一个类,然后继承RedisSerializer,再然后在配置RedisTemplate时使用)
StringRedisTemplate
通过查询StringRedisTemplate的源码,可以发现
public StringRedisTemplate() {
setKeySerializer(RedisSerializer.string());
setValueSerializer(RedisSerializer.string());
setHashKeySerializer(RedisSerializer.string());
setHashValueSerializer(RedisSerializer.string());
}
StringRedisTemplate将序列化方式全部设置为RedisSerializer.string()了。
查看一下RedisSerializer.string()
static RedisSerializer<String> string() {
return StringRedisSerializer.UTF_8;
}
可以发现使用的StringRedisSerializer来进行序列化的
请看实例代码
@Test
public void contextLoads() {
stringRedisTemplate.opsForValue().set("name","张三");
}
为什么中文变为2进制了呀,那是因为终端的问题。
大家使用redis-cli 连接时加一个 --raw参数就行了
总结
- redisTemplate
可以存储任意类型,但是key、value、hashkey、hashvalue都会默认使用jdk的Serializable序列化存储,当然也可以自定义序列化方式 - stringRedisTemplate
key、value、hashkey、hashvalue都只能存字符串。默认使用StringRedisSerializer来序列化