解决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>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。