zoukankan      html  css  js  c++  java
  • RedisTemplate和StringRedisTemplate的区别 RedisTemplate几种序列化方式比较

    一、redisTemplate和stringRedisTemplate对比

    RedisTemplate看这个类的名字后缀是Template,如果了解过Spring如何连接关系型数据库的,大概不会难猜出这个类是做什么的 ,它跟JdbcTemplate一样封装了对Redis的一些常用的操作,当然StringRedisTemplate跟RedisTemplate功能类似那么肯定就会有人问,为什么会需要两个Template呢,一个不就够了吗?其实他们两者之间的区别主要在于他们使用的序列化类。

    RedisTemplate使用的是 JdkSerializationRedisSerializer 序列化对象
    StringRedisTemplate使用的是 StringRedisSerializer 序列化String

    1、StringRedisTemplate

    • 主要用来存储字符串,StringRedisSerializer的泛型指定的是String。当存入对象时,会报错 :can not cast into String。
    • 可见性强,更易维护。如果过都是字符串存储可考虑用StringRedisTemplate。

    2、RedisTemplate

    • 可以用来存储对象,但是要实现Serializable接口。
    • 以二进制数组方式存储,内容没有可读性。

    二、redisTemplate序列化方式比较

    那有没有办法,可以序列化对象,可读性又强呢?

    • 1、手动转化成json串再存储。取出数据需要反序列化。
    • 2、使用其他序列化方式。

    spring-data-redis提供如下几种选择:

    • GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
    • Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的
    • JacksonJsonRedisSerializer: 序列化object对象为json字符串
    • JdkSerializationRedisSerializer: 序列化java对象
    • StringRedisSerializer: 简单的字符串序列化

    1、性能测试对比

    @Test
        public void testSerial(){
            UserPO userPO = new UserPO(1111L,"小明_testRedis1",25);
            List<Object> list = new ArrayList<>();
            for(int i=0;i<200;i++){
                list.add(userPO);
            }
            JdkSerializationRedisSerializer j = new JdkSerializationRedisSerializer();
            GenericJackson2JsonRedisSerializer g = new GenericJackson2JsonRedisSerializer();
            Jackson2JsonRedisSerializer j2 = new Jackson2JsonRedisSerializer(List.class);
    
    
            Long j_s_start = System.currentTimeMillis();
            byte[] bytesJ = j.serialize(list);
            System.out.println("JdkSerializationRedisSerializer序列化时间:"+(System.currentTimeMillis()-j_s_start) + "ms,序列化后的长度:" + bytesJ.length);
            Long j_d_start = System.currentTimeMillis();
            j.deserialize(bytesJ);
            System.out.println("JdkSerializationRedisSerializer反序列化时间:"+(System.currentTimeMillis()-j_d_start));
    
    
            Long g_s_start = System.currentTimeMillis();
            byte[] bytesG = g.serialize(list);
            System.out.println("GenericJackson2JsonRedisSerializer序列化时间:"+(System.currentTimeMillis()-g_s_start) + "ms,序列化后的长度:" + bytesG.length);
            Long g_d_start = System.currentTimeMillis();
            g.deserialize(bytesG);
            System.out.println("GenericJackson2JsonRedisSerializer反序列化时间:"+(System.currentTimeMillis()-g_d_start));
    
            Long j2_s_start = System.currentTimeMillis();
            byte[] bytesJ2 = j2.serialize(list);
            System.out.println("Jackson2JsonRedisSerializer序列化时间:"+(System.currentTimeMillis()-j2_s_start) + "ms,序列化后的长度:" + bytesJ2.length);
            Long j2_d_start = System.currentTimeMillis();
            j2.deserialize(bytesJ2);
            System.out.println("Jackson2JsonRedisSerializer反序列化时间:"+(System.currentTimeMillis()-j2_d_start));
        }

    结果:

    JdkSerializationRedisSerializer序列化时间:8ms,序列化后的长度:1325

    JdkSerializationRedisSerializer反序列化时间:4

    GenericJackson2JsonRedisSerializer序列化时间:52ms,序列化后的长度:17425

    GenericJackson2JsonRedisSerializer反序列化时间:60

    Jackson2JsonRedisSerializer序列化时间:4ms,序列化后的长度:9801

    Jackson2JsonRedisSerializer反序列化时间:4

    2、性能总结

    JdkSerializationRedisSerializer序列化后长度最小,Jackson2JsonRedisSerializer效率最高。

    如果综合考虑效率和可读性,牺牲部分空间,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用Jackson2JsonRedisSerializer

    如果空间比较敏感,效率要求不高,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用JdkSerializationRedisSerializer

    3、方案一、考虑效率和可读性,牺牲部分空间

    package com.example.demo.config.redisConfig;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    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.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @Configuration
    public class RedisConfig {
        @Bean(name = "redisTemplate")
        public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
            redisTemplate.setConnectionFactory(factory);
            redisTemplate.setKeySerializer(new StringRedisSerializer()); // key的序列化类型
    
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
            return redisTemplate;
        }
    }

    注: new Jackson2JsonRedisSerializer(Object.class)需要指明类型,例如:new Jackson2JsonRedisSerializer(User.class),否则会报错:

    java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.demo.bean.User。

    或者开启默认类型:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    这种方式存储时会自动带上类的全路径,占用部分空间:

     4、方案二、空间敏感,忽略可读性和效率影响

    @Configuration
    public class RedisConfig {
        @Bean(name = "redisTemplate")
        public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
            redisTemplate.setConnectionFactory(factory);
            redisTemplate.setKeySerializer(new StringRedisSerializer()); // key的序列化类型
            redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); // value的序列化类型
            return redisTemplate;
        }
    }

    注:该方式,对象需要实现接口:Serializable

    5、使用示例

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @WebAppConfiguration
    public class RedisTest {
        @Resource
        private RedisTemplate redisTemplate;
    
        @Test
        public void testRedis1(){
            User user = new User();
            user.setAge(11);
            user.setName("我是小王1");
            redisTemplate.opsForValue().set("user37",user);
            System.out.println(redisTemplate.getValueSerializer());
            System.out.println(redisTemplate.getKeySerializer());
            User result = (User) redisTemplate.opsForValue().get("user37");
            System.out.println(result);
        }
    }
  • 相关阅读:
    02安卓用户界面优化之(三)如何使用菜单
    07-业务敏捷:帮助DevOps快速落地的源动力
    转型之路:企业实施DevOps的常见路径和问题
    价值流分析:关于DevOps转型,我们应该从何处入手
    DevOps的衡量:你是否找到了DevOps的实施路线图
    DevOps的实施:到底是工具先行还是文化先行
    DevOps的价值:数字化转型时代,DevOps是必选项
    DevOps的“定义”:DevOps究竟要解决什么问题
    Jenkins产品经理是如何设计产品的
    关于DevOps组织和文化的那些趣事儿.
  • 原文地址:https://www.cnblogs.com/yifanSJ/p/9108673.html
Copyright © 2011-2022 走看看