Maison  >  Article  >  base de données  >  Comment configurer la séquence et la désérialisation de RedisTemplate dans Redis

Comment configurer la séquence et la désérialisation de RedisTemplate dans Redis

WBOY
WBOYavant
2023-06-03 21:25:081378parcourir

Séquence de configuration et désérialisation de RedisTemplate

Spring Data Redis fournit une excellente encapsulation pour faciliter l'utilisation des opérations Redis. Une classe RedisTemplate hautement encapsulée est fournie pour effectuer une série d'opérations Redis, et le pool de connexions est automatiquement géré en même temps, l'opération d'encapsulation de la transaction est transmise au conteneur pour traitement ;

Une variété de stratégies (RedisSerializer) sont fournies pour la « sérialisation et désérialisation » des données

La valeur par défaut est d'utiliser JdkSerializationRedisSerializer, ainsi que StringRedisSerializer, JacksonJsonRedisSerializer, OxmSerializer et GenericFastJsonRedisSerializer.

Introduction

JdkSerializationRedisSerializer : le scénario d'accès aux objets POJO, utilisant le propre mécanisme de sérialisation du JDK, sérialise la classe pojo via ObjectInputStream/ObjectOutputStream, et enfin la séquence d'octets sera stockée dans le serveur redis. Il s'agit de la stratégie de sérialisation par défaut actuelle.

StringRedisSerializer : lorsque la clé ou la valeur est une chaîne, la séquence d'octets des données est codée dans une chaîne selon le jeu de caractères spécifié. Il s'agit d'une encapsulation directe de "new String(bytes, charset)" et "string.getBytes". (jeu de caractères)". est la stratégie la plus légère et la plus efficace.

JacksonJsonRedisSerializer : l'outil jackson-json offre des capacités de conversion entre javabean et json. Il peut sérialiser les instances pojo au format json et les stocker au format redis, ou convertir les données au format json en instances pojo. Étant donné que l'outil Jackson doit spécifier explicitement le type de classe lors de la sérialisation et de la désérialisation, cette stratégie est légèrement plus compliquée à encapsuler. [Nécessite la prise en charge de l'outil jackson-mapper-asl]

GenericFastJsonRedisSerializer : une autre conversion entre javabean et json, et le type de classe doit également être spécifié.

OxmSerializer : offre la possibilité de convertir des javabeans en XML. Le support tiers actuellement disponible inclut jaxb, apache-xmlbeans ; les données stockées dans Redis seront des outils XML. Cependant, l'utilisation de cette stratégie rendra la programmation plus difficile et la plus efficace ; elle n'est pas recommandée ; [Nécessite la prise en charge du module spring-oxm]

Pratique

1) Dépendance (la version hérite de la version SpringBoot)

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

2) Classe RedisConfig

Ajoutez des beans, spécifiez la clé/valeur et la séquence de HashKey et HashValue Contient et désérialise en 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;
    }
}

Problème de sérialisation de RedisTemplate

Les règles de sérialisation et de désérialisation sont incohérentes, ce qui entraîne des problèmes de rapport d'erreurs

1. Configurez 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 Enregistrez la valeur

Cette fois, la fonction de rappel de redisTemplate est utilisée pour enregistrer le. value, qui est basée sur la méthode de sérialisation de chaîne de caractères pour stocker 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;
        });
    }

client redis : la valeur est une chaîne

Comment configurer la séquence et la désérialisation de RedisTemplate dans Redis

3 Obtenez la valeur

Cette fois, le résultat renvoyé est par défaut la méthode de sérialisation JdkSerializationRedisSerializer configurée en 1. . Configurez redisTemplate. Étant donné que les méthodes de sérialisation de stockage et de récupération ne sont pas uniformes, des erreurs se produiront.

	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);
    }

Détails du rapport d'erreur : la désérialisation a échoué


org.springframework.data.redis.serializer.SerializationException : impossible de désérialiser ; l'exception imbriquée est org.springframework.core.serializer.support.SerializationFailedException : échec de la désérialisation de la charge utile. tableau d'octets résultat de la sérialisation correspondante pour DefaultDeserializer ? ; l'exception imbriquée est java.io.StreamCorruptedException : en-tête de flux non valide : 31303030
...
Causé par : org.springframework.core.serializer.support.SerializationFailedException : échec de la désérialisation de la charge utile. Le tableau d'octets est-il le résultat de la sérialisation correspondante pour DefaultDeserializer ? ; l'exception imbriquée est java.io.StreamCorruptedException : en-tête de flux invalide : 31303030
sur org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
sur org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
sur org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:80)
... 39 de plus
Causé par : java.io.StreamCorruptedException : en-tête de flux non valide : 31303030
sur java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:899)
sur java.io.ObjectInputStream.(ObjectInputStream.java:357)
sur org.springframework.core.ConfigurableObjectInputStream.(ConfigurableObjectInputStream.java:63)
sur org.springframework.core.ConfigurableObjectInputStream.(ConfigurableObjectInputStream.java:49)
sur org.springframework.core serializer . .DefaultDeserializer.deserialize(DefaultDeserializer.java:68)
sur org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73)
... 41 de plus

Solution

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客户端数据展示

Comment configurer la séquence et la désérialisation de RedisTemplate dans Redis

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客户端数据展示

Comment configurer la séquence et la désérialisation de RedisTemplate dans Redis

c.不同点:

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer