Article directory
problem introduction
When we use RedisTemplate to write a piece of String data to Redis, the data can be inserted normally
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString() {
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("name","xiaotengteng"); //打断点追源码
System.out.println("name = "+valueOperations.get("name"));
}
But when you open the Redis client to view, or redis-cli view, you find:
Inserted data is serialized as bytes
reason
RedisTemplate can receive any Object as a value and write it to Redis:
It's just that the Object will be serialized into bytes before writing. The default is to use the JDK serialization tool: ObjectOutputStream , so to get the above results, try to track the source code:
Enter the RedisTemplate class: keySerializer, valueSerializer, hashKeySerializer, hashValueSerializer, serializers for ordinary strings and hash structures, to achieve serialization and deserialization
Default Jdk serializer
view source code
Break the point on the set method, and debug the source code:
The value passed in becomes a byte
Get the serializer for the value
Enter the default JDK serializer: JdkSerializationRedisSerializer
then go down
buffer
Convert java objects to bytes and write them to Redis: ObjectOutputStream, which is the long string of bytes we see
Disadvantages of this serialization method:
- poor readability
- Large memory usage
Other serializers:
- The key is usually a string, you can use: StringRedisSerializer
- value is usually an object object, you can use: Jackson2JsonRedisSerializer
Solution
Serialization of custom RedisTemplate
key:String & value:String
Create a new RedisConfig configuration class
package com.itheima.springdataredisdemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
@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.setHashValueSerializer(jsonRedisSerializer);
//返回
return template;
}
}
test
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Test
void testString() {
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("name","xiaotengteng");
System.out.println("name = "+valueOperations.get("name"));
}
The result is an error, and the error message is as follows:
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.core.JsonProcessingException
//需要添加依赖
pom.xml
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
Test: modify name successfully
key:String & value:Object
Create a new User class
package com.itheima.springdataredisdemo.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
}
test
@Test
void testSaveUser(){
redisTemplate.opsForValue().set("user",new User("杰克",21));
User user = (User) redisTemplate.opsForValue().get("user");
System.out.println(user);
}
Here, JSON serialization is used instead of the default JDK serialization method. The final result is as follows:
The overall readability has been greatly improved, and Java objects can be automatically serialized into JSON strings, and JSON can be automatically deserialized into Java objects when querying. However, it records the corresponding class name during serialization, in order to achieve automatic deserialization during query. This introduces additional memory overhead.
StringRedisTemplate
overview
In order to save memory space, instead of using the JSON serializer to process the value, we can use the String serializer uniformly, requiring only the key and value of the String type to be stored. When Java objects need to be stored, serialization and deserialization of objects are done manually.
Because the serialization and deserialization when storing and reading are implemented by ourselves, Spring Data Redis will not write class information into Redis.
This kind of usage is more common, so SpringDataRedis provides a subclass of RedisTemplate: StringRedisTemplate, the serialization method of its key and value is the String method by default.
Code
@SpringBootTest
class RedisStringTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testString() {
// 写入一条String数据
stringRedisTemplate.opsForValue().set("verify:phone:13600527634", "124143");
// 获取string数据
Object name = stringRedisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
// 创建对象
User user = new User("虎哥", 21);
// 手动序列化
String json = mapper.writeValueAsString(user);
// 写入数据
stringRedisTemplate.opsForValue().set("user:200", json);
// 获取数据
String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
// 手动反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println("user1 = " + user1);
}
}
test
At this point, let's take a look at the stored data again, and find that the class data is no longer there, saving our space~
Summarize
Two serialization practices of RedisTemplate:
-
Option One:
- Custom RedisTemplate
- Modify the serializer of RedisTemplate to GenericJackson2JsonRedisSerializer
-
Option II:
- Use StringRedisTemplate
- When writing to Redis, manually serialize the object to JSON
- When reading Redis, manually deserialize the read JSON into an object