解决redisTemplate向redis中插入String类型数据时出现乱码问题
作者:起名好难(# #)
前置知识
1.啥是redisTemplate?
redisTemplate是SpringDataRedis中的一个工具类,封装了各种对Redis的操作,并将不同数据类型的操作API封装到了不同的类型中
举例:
下面的语句表示将【"name","谷歌"】这个k-v存入到redis中
redisTemplate.opsForValue().set("name","谷歌");2.啥是序列化和反序列化?
序列化:将对象存入一个文件的过程。
反序列化:从一个文件中解析出对象。
问题描述
首先,这是一个Springboot+SpringDataRedis的项目
如果按照【前置知识】的例子中那样写,那么存入redis的将会是二进制数据,格式如下:

实际上这并不属于啥错误,将上面的二进制转化成String后,其实就是“谷歌”。
但这样可读性很差,且占用过多内存。
成因分析
省流:由于没有给自定义序列化方式,所以默认采用的是jdk序列化器进行序列化,导致最后存入的数据是二进制。
以下是详细分析过程:
这是如何调用redisTemplate并实现插入数据的一段代码:
@SpringBootTest
class SpringDataRedisDemoApplicationTests {
@Resource
private RedisTemplate redisTemplate;
@Test
void testString() {
// 写入String数据
redisTemplate.opsForValue().set("name","谷歌");
}
}其中set方法的入参数据类型为两个Object。
RedisTemplate可以接收任意Object作为值写入Redis

当没有自定义序列化方式时,默认会使用jdk序列化器,redisTemplate的源码中做了下面的定义:
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
@Override
public void afterPropertiesSet() {
...
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
...
}
}
jdk序列化器在底层会将Java对象转成字节进行存储,也就是之前看到的二进制数据。
解决方案
1.改什么?
redisTemplate的源码中其实规定了5种序列化器,其中四种默认均为null。
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
private @Nullable RedisSerializer<?> defaultSerializer;
private @Nullable RedisSerializer keySerializer = null;
private @Nullable RedisSerializer valueSerializer = null;
private @Nullable RedisSerializer hashKeySerializer = null;
private @Nullable RedisSerializer hashValueSerializer = null;
}那么只要能改变序列化的方式,就能改变存入redis的数据类型。
RedisSerializer这个接口的实现类有下面几种:

对于key一般使用 StringRedisSerializer ; (key一般是字符串)
而对于value一般使用 GenericJackson2JsonRedisSerializer 。(value可能是复杂的对象)
2.怎么改?
可以通过【配置类注入容器】来实现对序列化器的修改
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置连接工厂
template.setConnectionFactory(connectionFactory);
//创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashKeySerializer(jsonRedisSerializer);
//返回
return template;
}
}在注入redisTemplate对象时,指定其泛型为<String,Object>
@SpringBootTest
class SpringDataRedisDemoApplicationTests {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Test
void testString() {
// 写入String数据
redisTemplate.opsForValue().set("name","百度");
// 获取String数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);
}
}3.报错怎么办?
可能会报下面的错
Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder
at stu.demo.springdataredisdemo.config.RedisConfig.redisTemplate(RedisConfig.java:20)
引入下面的依赖即可
<!--Jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
