redisTemplate和stringRedisTemplate对比、redisTemplate几种序列化方式比较

    技术2022-07-16  61

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

     

    Processed: 0.018, SQL: 9