Summary of serialization methods of SpringDataRedis

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:

1674482108810

Inserted data is serialized as bytes

1674482696263

reason

RedisTemplate can receive any Object as a value and write it to Redis:

OEMcbuu

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

1674484237279

Default Jdk serializer

1674484416134

view source code

Break the point on the set method, and debug the source code:

The value passed in becomes a byte

1674483314408

Get the serializer for the value

1674483412612

Enter the default JDK serializer: JdkSerializationRedisSerializer

1674483560527

then go down

1674483612044

buffer

1674483738228

Convert java objects to bytes and write them to Redis: ObjectOutputStream, which is the long string of bytes we see

1674483914751

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

Please add a picture description

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

1674570714996

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:

1674571441366

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.

Ip9TKSY

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.

image-20230131150855477

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~

image-20230131151050169

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

Guess you like

Origin blog.csdn.net/Htupc/article/details/128818193