>  기사  >  데이터 베이스  >  Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법

Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법

WBOY
WBOY앞으로
2023-06-03 21:25:081378검색

RedisTemplate 구성 순서 및 역직렬화

Spring Data Redis는 Redis 작업 사용을 용이하게 하기 위해 탁월한 캡슐화를 제공합니다. 일련의 Redis 작업을 수행하기 위해 고도로 캡슐화된 RedisTemplate 클래스가 제공되며, 연결 풀이 자동으로 관리되는 동시에 트랜잭션 캡슐화 작업이 처리를 위해 컨테이너로 넘겨집니다.

데이터의 "직렬화 및 역직렬화"를 위해 다양한 전략(RedisSerializer)이 제공됩니다.

기본값은 JdkSerializationRedisSerializer를 사용하는 것이며 StringRedisSerializer, JacksonJsonRedisSerializer, OxmSerializer 및 GenericFastJsonRedisSerializer도 사용됩니다.

Introduction

JdkSerializationRedisSerializer: POJO 객체 액세스 시나리오는 JDK 자체 직렬화 메커니즘을 사용하여 ObjectInputStream/ObjectOutputStream을 통해 pojo 클래스를 직렬화하고 마지막으로 바이트 시퀀스가 ​​redis-server에 저장됩니다. 이것이 현재 기본 직렬화 전략입니다.

StringRedisSerializer: 키 또는 값이 문자열인 경우 데이터의 바이트 시퀀스는 지정된 문자 집합에 따라 문자열로 인코딩됩니다. 이는 "new String(bytes, charset)" 및 "string.getBytes"를 직접 캡슐화한 것입니다. (문자 집합)". 가장 가볍고 효율적인 전략입니다.

JacksonJsonRedisSerializer: jackson-json 도구는 javabean과 json 간의 변환 기능을 제공합니다. 이 도구는 pojo 인스턴스를 json 형식으로 직렬화하고 이를 redis에 저장하거나 json 형식 데이터를 pojo 인스턴스로 변환할 수 있습니다. Jackson 도구는 직렬화 및 역직렬화 시 클래스 유형을 명시적으로 지정해야 하기 때문에 이 전략은 캡슐화하기가 약간 더 복잡합니다. [jackson-mapper-asl 도구 지원 필요]

GenericFastJsonRedisSerializer: javabean과 json 간의 또 다른 변환과 클래스 유형도 지정해야 합니다.

OxmSerializer: Javabeans를 xml로 변환하는 기능을 제공합니다. 현재 사용 가능한 3자 지원에는 jaxb, apache-xmlbeans가 포함됩니다. redis에 저장된 데이터는 xml 도구입니다. 그러나 이 전략을 사용하면 프로그래밍이 더 어려워지고 효율성도 떨어지므로 권장되지 않습니다. [spring-oxm 모듈 지원 필요]

Practice

1) 종속성(버전은 SpringBoot 버전을 상속함)

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2) RedisConfig 클래스

빈을 추가하고, 키/값과 HashKey 및 HashKey 시퀀스를 지정합니다. HashValue FastJson을 포함하고 역직렬화합니다.

package com.sleb.springcloud.common.config;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
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.GenericToStringSerializer;
/**
 * redis配置
 * @author 追到乌云的尽头找太阳(Jacob)
 **/
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用 GenericFastJsonRedisSerializer 替换默认序列化
        GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
        // 设置key和value的序列化规则
        redisTemplate.setKeySerializer(new GenericToStringSerializer<>(Object.class));
        redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
        // 设置hashKey和hashValue的序列化规则
        redisTemplate.setHashKeySerializer(new GenericToStringSerializer<>(Object.class));
        redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
        // 设置支持事物
        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

RedisTemplate 직렬화 문제

직렬화 및 역직렬화 규칙이 일치하지 않아 오류 보고 문제 발생

1. redisTemplate 구성

<!-- redis数据源 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大空闲数 -->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <!-- 最大空连接数 -->
        <property name="maxTotal" value="${redis.maxTotal}"/>
        <!-- 最大等待时间 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
        <!-- 返回连接时,检测连接是否成功 -->
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    </bean>
<!-- Spring-data-redis连接池管理工厂 -->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <!-- IP地址 -->
        <property name="hostName" value="${redis.host}"/>
        <!-- 端口号 -->
        <property name="port" value="${redis.port}"/>
        <!-- 密码 -->
<!--        <property name="password" value="${redis.password}"/>-->
        <!-- 超时时间 默认2000 -->
        <property name="timeout" value="${redis.timeout}"/>
        <!-- 连接池配置引用 -->
        <property name="poolConfig" ref="poolConfig"/>
        <!-- 是否使用连接池 -->
        <property name="usePool" value="true"/>
        <!-- 指定使用的数据库 -->
        <property name="database" value="0"/>
    </bean>
<!-- redis template definition -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory"/>
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
    </bean>

2. 값 저장

이번에는 값이 저장되며 redisTemplate의 콜백 함수가 사용됩니다. 문자를 기반으로 redisValue

    public void testRedisListPush() {
        String redisKey = "testGoodsKey";
        List<String> redisValues = Arrays.asList("10002001", "10002002");
        // 使用管道向redis list结构中批量插入元素
        redisTemplate.executePipelined((RedisConnection redisConnection) -> {
            // 打开管道
            redisConnection.openPipeline();
            // 给本次管道内添加,一次性执行的多条命令
            for (String redisValue : redisValues) {
                redisConnection.rPush(redisKey.getBytes(), redisValue.getBytes());
            }
            return null;
        });
    }

redis 클라이언트를 저장하는 문자열 직렬화 방법: 값은 문자열

Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법

3입니다. 값을 가져옵니다

이번 반환된 결과는 기본적으로 1. 구성에서 구성한 JdkSerializationRedisSerializer 직렬화 방법입니다. redisTemplate. 저장 및 검색의 직렬화 방법이 균일하지 않기 때문에 오류가 발생합니다.

	public void testRedisListPop() {
        String redisKey = "testGoodsKey";
        // 使用管道从redis list结构中批量获取元素
        List<Object> objects = redisTemplate.executePipelined((RedisConnection redisConnection) -> {
            // 打开管道
            redisConnection.openPipeline();
            for (int i = 0; i < 2; i++) {
                redisConnection.rPop(redisKey.getBytes());
            }
            return null;
        });
        System.out.println(objects);
    }

오류 보고 세부정보: 역직렬화 실패


org.springframework.data.redis.serializer.SerializationException: 중첩된 예외는 org.springframework.core.serializer.support.SerializationFailedException: 페이로드 역직렬화에 실패했습니다. 바이트 배열은 DefaultDeserializer에 해당하는 직렬화 결과입니다. 중첩된 예외는 java.io.StreamCorruptedException: 잘못된 스트림 헤더: 31303030
...
원인: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload 입니다. 바이트 배열은 DefaultDeserializer에 대한 해당 직렬화의 결과입니까? 중첩된 예외는 java.io.StreamCorruptedException:valid stream header: 31303030
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
입니다. at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:80)
... 39 더 보기
원인: java.io.StreamCorruptedException: 잘못된 스트림 헤더: 31303030
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:899)
at java.io.ObjectInputStream.(ObjectInputStream.java:357)
org.springframework.core.ConfigurableObjectInputStream.(ConfigurableObjectInputStream.java:63)
org.springframework.core.ConfigurableObjectInputStream.(ConfigurableObjectInputStream.java:49)
org.springframework.core . .DefaultDeserializer.deserialize(DefaultDeserializer.java:68)
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73)
... 41개 더

솔루션

1.

需要在redisTemplate.executePipelined入参中再加一个参数:redisTemplate.getStringSerializer(),取值成功,解决问题!!

    public void testRedisListPop() {
        String redisKey = "testGoodsKey";
        // 使用管道从redis list结构中批量获取元素
        List<Object> objects = redisTemplate.executePipelined((RedisConnection redisConnection) -> {
            // 打开管道
            redisConnection.openPipeline();
            for (int i = 0; i < 2; i++) {
                redisConnection.rPop(redisKey.getBytes());
            }
            return null;
        }, redisTemplate.getStringSerializer());
        System.out.println(objects);
    }

总结

1、使用原生redisTemplate操作数据和redisTemplate回调函数操作数据注意点:

a.原生redisTemplate操作数据

代码

    public void testRedisListPush() {
        String redisKey = "testGoodsKey";
        List<String> redisValues = Arrays.asList("10002001", "10002002");
        redisValues.forEach(redisValue -> redisTemplate.opsForList().rightPush(redisKey, redisValue));
    }

redis客户端数据展示

Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법

b.redisTemplate回调函数操作数据

代码

    public void testRedisListPush() {
        String redisKey = "testGoodsKey";
        List<String> redisValues = Arrays.asList("10002001", "10002002");
        // 使用管道向redis list结构中批量插入元素
        redisTemplate.executePipelined((RedisConnection redisConnection) -> {
            // 打开管道
            redisConnection.openPipeline();
            // 给本次管道内添加,一次性执行的多条命令
            for (String redisValue : redisValues) {
                redisConnection.rPush(redisKey.getBytes(), redisValue.getBytes());
            }
            return null;
        });
    }

redis客户端数据展示

Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법

c.不同点:

原生redisTemplate操作数据序列化方式是和redis配置统一的,redisTemplate回调函数操作数据序列化方式是自定义的。存值取值是需要注意。

위 내용은 Redis에서 RedisTemplate의 순서 및 역직렬화를 구성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제