开发者

解决redisTemplate向redis中插入String类型数据时出现乱码问题

开发者 https://www.devze.com 2023-12-21 10:23 出处:网络 作者: 起名好难(# #)
目录前置知识1.啥是RedisTemplate?2.啥是序列化和反序列化?问题描述成因分析解决方案1.改什么?2.怎么改?3.报错怎么办?总结前置知识
目录
  • 前置知识
    • 1.啥是RedisTemplate?
    • 2.啥是序列化和反序列化?
  • 问题描述
    • 成因分析
      • 解决方案
        • 1.改什么?
        • 2.怎么改?
        • 3.报错怎么办?
      • 总结

        前置知识

        1.啥是redisTemplate?

        redisTemplate是SpringDataRedis中的一个工具类,封装了各种对Redis的操作,php并将不同数据类型的操作API封装到了不同的类型中

        举例:

        下面的语句表示将【"name","谷歌"编程】这个k-v存入到redis中

        redisTemplate.opsForValue().set("name","谷歌");

        2.啥是序列化和反序列化?

        序列化:将对象存入一个文件的过程。

        反序列化:从一个文件中解析出对象。

        问题描述

        首先,这是一个Springboot+SpringDataRedis的项目

        如果按照【前置知识】的例子中那样写,那么存入redis的将会是二进制数据,格式如下:

        解决redisTemplate向redis中插入String类型数据时出现乱码问题

        实际上这并不属于啥错误,将上面的二进制转化成String后,其实就是“谷歌”。

        但这样可读性很差编程,且占用过多内存。

        成因分析

        省流:由于没有给自定义序列化方式,所以默认采用的是jdk序列化器进行序列化,导致最后存入的数据是二进制。

        以下是详细分析过程:

        这是如何调用redisTemplate并实现插入数据的一段代码:

        @SpringBootTest
        class SpringDataRedisDemoApplicationTests {
         
            @Resource
            private RedisTemplate redisTemplate;
         
            @Test
            void testString() {
                // 写入String数据
                redisTemplate.opsForValue().set("name","谷歌");
            }
         
        }

        其中set方法的入参数据类型为两个Object。

        RedisTemplate可以接收任意Object作为值写入Redis

        解决redisTemplate向redis中插入String类型数据时出现乱码问题

        当没有自定义序列化方式时,默认会使用jdk序列化器,redisTemplate的源码中做了下面的定义:

        public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
         
        	@Override
        	public void afterPropertiesSet() {
                ...
        		if (defaultSerializer == null) {
         
        			defaultSerializer = new JdkSerializationRedisSerializer(
        					classLoader != null ? classLoader : this.getClass().getClassLoader());
        		}
                ...
            }
        }
           

        jdk序列化器在底层会将Java对象转成字节进行存储,也就是之前看到的二进制数据。

        解决方案

        1.改什么?

        redisTemplate的源码中其实规定了5种序列化器,其中四种默认均为null。

        public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
         
        	private @Nullable RedisSerializer<?> defaultSerializer;
        	private @Nullable RedisSerializer keySerializer = null;
        	private @Nullable RedisSerializer valueSerializer = null;
        	private @Nullable RedisSerializer hashKeySerializer = null;
        	private @Nullable RedisSerializer hashValueSerializer = null;
        }

        那么只要能改变序列化的方式,就能改变存入redis的数据类型。

        RedisSerializer这个接口的实现类有下面几种:

        解决redisTemplate向redis中插入String类型数据时出现乱码问题

        对于key一般使用 StringRedisSerializer  ; (key一般是字符串)

        而对于value一般使用 GenericJackson2jsonRedisSerializer 。(value可能是复杂的对象)

        2.怎么改?

        可以通过【配置类注入容器】来实现对序列化器的修改

        @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.setHashKeySerializer(jsonRedisSerializer);
                //返回
                return template;
            }
        }

        在注入redisTemplate对象时,指定其泛型为<String,Object>

        @SpringBootTest
        class SpringDataRedisDemoApplicationTests {
         
            @Autowired
            private RedisTemplate<String,Object> redisTemplate;
         
         
            @Test
            void testString() {
                // 写入String数据
                redisTemplate.opsForValue().set("name","百度");
                // 获取String数据
                Object name = redisTemplate.opsForValue().get("name");
                System.out.println(name);
            }
         
        }

        3.报错怎么办?

        可能会报下面的错

        Caused by: java.lang.NoClassDefFoundError: com/fasterXML/jackson/databind/jsontype/impl/StdTypeResolverBuilder

            at stu.demo.springdataredisdemo.config.RedisConfig.redisTemplate(RedisConfig.java:20)

        引入下面的依赖即可

        <!--Jackson-->
        <dependency>
            <groupId>com.fasterxml.j编程客栈ackson.core</groupId>
            <android;artifactId>jackson-databind</artifactId>
        </dependency>

        总结

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

        0

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        关注公众号