java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > redisTemplate向redis中插入String类型数据时出现乱码

解决redisTemplate向redis中插入String类型数据时出现乱码问题

作者:起名好难(# #)

这篇文章主要介绍了解决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>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文