设为首页 收藏本站
查看: 600|回复: 0

[经验分享] 关于Spring-Data-Redis的几种比较

[复制链接]

尚未签到

发表于 2018-11-3 07:25:45 | 显示全部楼层 |阅读模式
  关于Spring Data redis几种对象序列化的比较
  Spring
  问题
  

最近在整一个spring data redis,网上有一本《Spring Data》的电子书(我一个朋友正在翻译,应该今年会有中文版出来,人邮的),下载来看了一下,其中第8章讲到了Spring data对redis的支持。  
redis虽然提供了对list set hash等数据类型的支持,但是没有提供对POJO对象的支持,底层都是把对象序列化后再以字符串的方式存储的。因此,Spring data提供了若干个Serializer,主要包括:
  

  JacksonJsonRedisSerializer
  JdkSerializationRedisSerializer
  OxmSerializer
  参见:http://static.springsource.org/spring-data/data-keyvalue/docs/1.0.x/api/
  这里,我第一是想测试一下三者的使用,第二是想看看它们的使用效果。
  准备工作
  下载源码
  我直接在《Spring Data》书的源码基础上改,从这下载书的源码:https://github.com/SpringSource/spring-data-book
  打开redis子项目,由于是以Maven组织的,所以不用关心包的问题。
  添加一个测试的Entity
  由于我们希望测试使用Redis保存POJO对象,因此我们在com.oreilly.springdata.redis包下创建一个User对象,如下所示:
  Java代码  收藏代码
  package com.oreilly.springdata.redis;
  import javax.xml.bind.annotation.XmlAccessType;
  import javax.xml.bind.annotation.XmlAccessorType;
  import javax.xml.bind.annotation.XmlAttribute;
  import javax.xml.bind.annotation.XmlRootElement;
  import java.io.Serializable;
  /**


  • @author : stamen
  •   @date: 13-7-16
      */
      @XmlAccessorType(XmlAccessType.FIELD)
      @XmlRootElement(name = "user")

      public>  @XmlAttribute
      private String userName;
      @XmlAttribute
      private int age;
      public String getUserName() {
      return userName;
      }
      public void setUserName(String userName) {
      this.userName = userName;
      }
      public int getAge() {
      return age;
      }
      public void setAge(int age) {
      this.age = age;
      }
      }
      由于后面,我们需要使用OXM及Jackson将进行对象序列,为了控制对象的序列化,因此打上了JSR 175注解。

  更改ApplicationConfig
  ApplicationConfig是Spring容器的配置类,要根据你的环境进行更改,我的更改为:
  Java代码  收藏代码
  package com.oreilly.springdata.redis;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.data.redis.connection.RedisConnectionFactory;
  import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  import org.springframework.data.redis.core.RedisTemplate;
  import org.springframework.data.redis.serializer.OxmSerializer;
  import org.springframework.data.redis.serializer.RedisSerializer;
  import org.springframework.data.redis.serializer.SerializationException;
  import org.springframework.oxm.jaxb.Jaxb2Marshaller;
  import javax.xml.bind.JAXBContext;
  import javax.xml.bind.Marshaller;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  /**


  •   @author Jon Brisbin
      */
      @Configuration

      public abstract>  @Bean
      public RedisConnectionFactory redisConnectionFactory() {
      JedisConnectionFactory cf = new JedisConnectionFactory();
      cf.setHostName("10.188.182.140");
      cf.setPort(6379);
      cf.setPassword("superman");
      cf.afterPropertiesSet();
      return cf;
      }
      @Bean
      public RedisTemplate redisTemplate() {
      RedisTemplate rt = new RedisTemplate();
      rt.setConnectionFactory(redisConnectionFactory());
      return rt;
      }
      private static Map jaxbContextHashMap = new ConcurrentHashMap();
      @Bean
      public OxmSerializer oxmSerializer() throws Throwable{
      Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
      Map properties = new HashMap();//创建映射,用于设置Marshaller属性
      properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);   //放置xml自动缩进属性
      properties.put(Marshaller.JAXB_ENCODING,"utf-8");   //放置xml自动缩进属性
      jaxb2Marshaller.setClassesToBeBound(User.class);//映射的xml类放入JAXB环境中
      jaxb2Marshaller.setMarshallerProperties(properties);//设置Marshaller属性
      return  new OxmSerializer(jaxb2Marshaller,jaxb2Marshaller);
      }
      public static enum StringSerializer implements RedisSerializer {
      INSTANCE;
      

    @Override  
    public byte[] serialize(String s) throws SerializationException {
      return (null != s ? s.getBytes() : new byte[0]);
      
    }
      

      
    @Override
      
    public String deserialize(byte[] bytes) throws SerializationException {
      if (bytes.length > 0) {
      return new String(bytes);
      } else {
      return null;
      }
      
    }
      

      }
      public static enum LongSerializer implements RedisSerializer {
      INSTANCE;
      

    @Override  
    public byte[] serialize(Long aLong) throws SerializationException {
      if (null != aLong) {
      return aLong.toString().getBytes();
      } else {
      return new byte[0];
      }
      
    }
      

      
    @Override
      
    public Long deserialize(byte[] bytes) throws SerializationException {
      if (bytes.length > 0) {
      return Long.parseLong(new String(bytes));
      } else {
      return null;
      }
      
    }
      

      }
      public static enum IntSerializer implements RedisSerializer {
      INSTANCE;
      

    @Override  
    public byte[] serialize(Integer i) throws SerializationException {
      if (null != i) {
      return i.toString().getBytes();
      } else {
      return new byte[0];
      }
      
    }
      

      
    @Override
      
    public Integer deserialize(byte[] bytes) throws SerializationException {
      if (bytes.length > 0) {
      return Integer.parseInt(new String(bytes));
      } else {
      return null;
      }
      
    }
      

      }

  }
  1)redisConnectionFactory()配置了如何连接Redsi服务器(如何安装Redis,参见:http://redis.io/download)
  2)oxmSerializer()是我新增的,用于定义一个基于Jaxb2Marshaller的OxmSerializer Bean(后面将会用到)
  编写测试用例
  

打开KeyValueSerializersTest,我们几个额外的测试用例都将写在该测试类中:   

  使用JdkSerializationRedisSerializer序列化
  Java代码  收藏代码
  @Test
  public void testJdkSerialiable() {
  RedisTemplate redis = new RedisTemplate();
  redis.setConnectionFactory(connectionFactory);
  redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
  redis.setValueSerializer(new JdkSerializationRedisSerializer());
  redis.afterPropertiesSet();
  

ValueOperations ops = redis.opsForValue();  

  
User user1 = new User();
  
user1.setUserName("user1");
  
user1.setAge(20);
  

  
String key1 = "users/user1";
  
User user11 = null;
  

  
long begin = System.currentTimeMillis();
  
for (int i = 0; i < 100; i++) {
  ops.set(key1,user1);
  user11 = (User)ops.get(key1);
  
}
  
long time = System.currentTimeMillis() - begin;
  
System.out.println("jdk time:"+time);
  
assertThat(user11.getUserName(),is("user1"));
  

  }
  JdkSerializationRedisSerializer支持对所有实现了Serializable的类进行序列化。运行该测试用例,我们通过redis-cli 通过“users/user1”键可以查看到对应的值,内容如下:
  引用
  redis 127.0.0.1:6379> get users/user1
  &quot;\xac\xed\x00\x05sr\x00!com.oreilly.springdata.redis.User\xb1\x1c \n\xcd\xed%\xd8\x02\x00\x02I\x00\x03ageL\x00\buserNamet\x00\x12Ljava/lang/String;xp\x00\x00\x00\x14t\x00\x05user1&quot;
  通过strlen查看对应的字符长度:
  引用
  redis 127.0.0.1:6379> strlen users/user1
  (integer) 104
  上面的代码共进行了100次的存储和获取,其所花时间如下(毫秒):
  引用
  jdk time:266
  使用JacksonJsonRedisSerializer序列化
  Java代码  收藏代码
  @Test
  public void testJacksonSerialiable() {
  RedisTemplate redis = new RedisTemplate();
  redis.setConnectionFactory(connectionFactory);
  redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
  redis.setValueSerializer(new JacksonJsonRedisSerializer(User.class));
  redis.afterPropertiesSet();
  

ValueOperations ops = redis.opsForValue();  

  
User user1 = new User();
  
user1.setUserName("user1");
  
user1.setAge(20);
  

  
User user11 = null;
  
String key1 = "json/user1";
  

  
long begin = System.currentTimeMillis();
  
for (int i = 0; i < 100; i++) {
  ops.set(key1,user1);
  user11 = (User)ops.get(key1);
  
}
  
long time = System.currentTimeMillis() - begin;
  

  
System.out.println("json time:"+time);
  
assertThat(user11.getUserName(),is("user1"));
  

  }
  

运行后,查看redis的内容及内容长度:   

  引用
  redis 127.0.0.1:6379> get json/user1
  &quot;{\&quot;userName\&quot;:\&quot;user1\&quot;,\&quot;age\&quot;:20}&quot;
  redis 127.0.0.1:6379> strlen json/user1
  (integer) 29
  

执行花费时间为:   

  引用
  

json time:224   

  使用OxmSerialiable序列化
  Java代码  收藏代码
  @Test
  public void testOxmSerialiable() throws Throwable{
  RedisTemplate redis = new RedisTemplate();
  redis.setConnectionFactory(connectionFactory);
  redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
  

redis.setValueSerializer(oxmSerializer);  
redis.afterPropertiesSet();
  

  
ValueOperations ops = redis.opsForValue();
  

  
User user1 = new User();
  
user1.setUserName("user1");
  
user1.setAge(20);
  

  
User user11 = null;
  
String key1 = "oxm/user1";
  

  
long begin = System.currentTimeMillis();
  
for (int i = 0; i < 100; i++) {
  ops.set(key1,user1);
  user11 = (User)ops.get(key1);
  
}
  
long time = System.currentTimeMillis() - begin;
  

  
System.out.println("oxm time:"+time);
  
assertThat(user11.getUserName(),is("user1"));
  

  }
  

运行后,查看redis的内容及内容长度:   

  引用
  redis 127.0.0.1:6379> get oxm/user1
  &quot;\n\n&quot;
  redis 127.0.0.1:6379> strlen oxm/user1
  (integer) 90
  

执行花费时间为:   

  引用
  

oxm time:335   

  小结
  

从执行时间上来看,JdkSerializationRedisSerializer是最高效的(毕竟是JDK原生的),但是是序列化的结果字符串是最长的。JSON由于其数据格式的紧凑性,序列化的长度是最小的,时间比前者要多一些。而OxmSerialiabler在时间上看是最长的(当时和使用具体的Marshaller有关)。所以个人的选择是倾向使用JacksonJsonRedisSerializer作为POJO的序列器。   

  原文地址:http://stamen.iteye.com/blog/1907984



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-630001-1-1.html 上篇帖子: linux下安装redis 下篇帖子: Spring Boot + spring-data-redis
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表