springboot系列11、redisTemplate和stringRedisTemplate對比、redisTemplate幾種序列化方式比較

1、redisTemplate和stringRedisTemplate對比

  RedisTemplate看這個類的名字後綴是Template,若是瞭解過Spring如何鏈接關係型數據庫的,大概不會難猜出這個類是作什麼的 ,它跟JdbcTemplate同樣封裝了對Redis的一些經常使用的操做,固然StringRedisTemplate跟RedisTemplate功能相似那麼確定就會有人問,爲何會須要兩個Template呢,一個不就夠了嗎?其實他們二者之間的區別主要在於他們使用的序列化類。
RedisTemplate使用的是 JdkSerializationRedisSerializer 序列化對象
StringRedisTemplate使用的是 StringRedisSerializer 序列化String

一、StringRedisTemplate

  • 主要用來存儲字符串,StringRedisSerializer的泛型指定的是String。當存入對象時,會報錯 :can not cast into String。
  • 可見性強,更易維護。若是過都是字符串存儲可考慮用StringRedisTemplate。

二、RedisTemplate

  • 能夠用來存儲對象,可是要實現Serializable接口。
  • 以二進制數組方式存儲,內容沒有可讀性。

2、redisTemplate序列化方式比較

那有沒有辦法,能夠序列化對象,可讀性又強呢?java

  • 一、手動轉化成json串再存儲。取出數據須要反序列化。
  • 二、使用其餘序列化方式。

spring-data-redis提供以下幾種選擇:redis

  • GenericToStringSerializer: 能夠將任何對象泛化爲字符串並序列化
  • Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer其實是同樣的
  • JacksonJsonRedisSerializer: 序列化object對象爲json字符串
  • JdkSerializationRedisSerializer: 序列化java對象
  • StringRedisSerializer: 簡單的字符串序列化

一、性能測試對比

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

結果:spring

JdkSerializationRedisSerializer序列化時間:8ms,序列化後的長度:1325
JdkSerializationRedisSerializer反序列化時間:4
GenericJackson2JsonRedisSerializer序列化時間:52ms,序列化後的長度:17425
GenericJackson2JsonRedisSerializer反序列化時間:60
Jackson2JsonRedisSerializer序列化時間:4ms,序列化後的長度:9801
Jackson2JsonRedisSerializer反序列化時間:4數據庫

二、性能總結

  • JdkSerializationRedisSerializer序列化後長度最小,Jackson2JsonRedisSerializer效率最高。
  • 若是綜合考慮效率和可讀性,犧牲部分空間,推薦key使用StringRedisSerializer,保持的key簡明易讀;value可使用Jackson2JsonRedisSerializer
  • 若是空間比較敏感,效率要求不高,推薦key使用StringRedisSerializer,保持的key簡明易讀;value可使用JdkSerializationRedisSerializer

三、方案1、考慮效率和可讀性,犧牲部分空間

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),不然會報錯:
json

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

或者開啓默認類型:app

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

這種方式存儲時會自動帶上類的全路徑,佔用部分空間:性能

 

四、方案2、空間敏感,忽略可讀性和效率影響

@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測試

五、使用示例

@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);
    }
}
相關文章
相關標籤/搜索