起因是我在项目部署的时候有一个接口,本地跑起来没有问题,在linux服务器上面一开始跑起来也没有问题,后面突然就报错了。问同事说也没有另外部署覆盖我的接口。
后面排查是同事提供了一个rpc接口,这个接口有修改RedisTemplate 序列化器的代码,调完那个rpc接口,再调这个接口就会出现序列化的问题。然后进行代码自测,发现里面存在一些以前没注意的问题。
RedisTemplate的定义如下
@Configuration
public class RedisConfig {
@Bean("redisTemplate")
//一开始以为是没有加@Primary注解的缘故,导致系统不知道使用哪一个RedisTemplate,后面发现不是,就也没有注释掉
@Primary
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
template.setValueSerializer(RedisSerializer.json());
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
@Bean("redisStringTemplate")
public RedisTemplate<String, String> redisStringTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
template.setValueSerializer(RedisSerializer.string());
template.setHashValueSerializer(RedisSerializer.string());
template.afterPropertiesSet();
return template;
}
}
进行redis测试的代码
@SpringBootTest(classes = XiotDeviceApplication.class)
public class RedisTest {
@Resource(name = "redisStringTemplate")
RedisTemplate<String, String> stringTemplate;
@Resource(name = "redisTemplate")
private RedisTemplate<String, Object> redisTemplate;
@Test
public void redisTest2() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("123", "asd");
jsonObject.put("234", "fff");
stringTemplate.opsForValue().set("yu", jsonObject.toJSONString());
redisTemplate.opsForValue().set("yu2",jsonObject.toJSONString());
redisTemplate.opsForValue().set("yu3",jsonObject);
String yu = stringTemplate.opsForValue().get("yu");
String yu2 = stringTemplate.opsForValue().get("yu2");
Object yu3 = redisTemplate.opsForValue().get("yu3");
Object yu4 = redisTemplate.opsForValue().get("yu2");
System.out.println("yu4 = " + yu4);
}
}
生成的代码结果
一开始我感觉非常奇怪,明明是字符串格式化的存到redis变成了json格式,而使用json格式化的却变成了字符串格式。非常不能理解。
直到我测试了key=yu3的redis数据想通了
key=yu的数据存储都是字符串序列化,取出来也是字符串的格式 只是我使用的redis查看工具会做一个格式化的展示。
key=yu2的数据,使用json序列化,但是存储的数据是字符串,存到redis里面也是字符串,会对原有的双引号做转义,数据取出来的时候就会出现转义符。
key=yu3的数据,使用json序列化,存储的数据是对象,在redis里面也是字符串,查看工具本身做了格式化展示。但是会加上"@class": "com.alibaba.fastjson.JSONObject"标识是哪一个类,这样在取出来的时候也会序列化成指定的类。
总结:使用opsForValue()存储到redis里面的都是string格式,但是一些redis连接工具会对展示做格式化,序列化器使用在jvm中,跟redis存储没有什么关系,负责什么样的字符存储到redis或redis中读出来的字符展现成什么样。