本文轉自http://stamen.iteye.com/blog/1907984
問題
最近在整一個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對象,如下所示:
由於后面,我們需要使用OXM及Jackson將進行對象序列,為了控制對象的序列化,因此打上了JSR 175注解。
更改ApplicationConfig
ApplicationConfig是Spring容器的配置類,要根據你的環境進行更改,我的更改為:
1)redisConnectionFactory()配置了如何連接Redsi服務器(如何安裝Redis,參見:http://redis.io/download)
2)oxmSerializer()是我新增的,用於定義一個基於Jaxb2Marshaller的OxmSerializer Bean(后面將會用到)
編寫測試用例
打開KeyValueSerializersTest,我們幾個額外的測試用例都將寫在該測試類中:
使用JdkSerializationRedisSerializer序列化
JdkSerializationRedisSerializer支持對所有實現了Serializable的類進行序列化。運行該測試用例,我們通過redis-cli 通過“users/user1”鍵可以查看到對應的值,內容如下:
redis 127.0.0.1:6379> get users/user1
"\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"
通過strlen查看對應的字符長度:
redis 127.0.0.1:6379> strlen users/user1
(integer) 104
上面的代碼共進行了100次的存儲和獲取,其所花時間如下(毫秒):
使用JacksonJsonRedisSerializer序列化
@Test public void testJacksonSerialiable() { RedisTemplate<String, Object> redis = new RedisTemplate<String, Object>(); redis.setConnectionFactory(connectionFactory); redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE); redis.setValueSerializer(new JacksonJsonRedisSerializer<User>(User.class)); redis.afterPropertiesSet(); ValueOperations<String, Object> 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
"{\"userName\":\"user1\",\"age\":20}"
redis 127.0.0.1:6379> strlen json/user1
(integer) 29
執行花費時間為:
json time:224
使用OxmSerialiable序列化
@Test public void testOxmSerialiable() throws Throwable{ RedisTemplate<String, Object> redis = new RedisTemplate<String, Object>(); redis.setConnectionFactory(connectionFactory); redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE); redis.setValueSerializer(oxmSerializer); redis.afterPropertiesSet(); ValueOperations<String, Object> 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
"<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<user age=\"20\" userName=\"user1\"/>\n"
redis 127.0.0.1:6379> strlen oxm/user1
(integer) 90
執行花費時間為:
oxm time:335
小結
從執行時間上來看,JdkSerializationRedisSerializer是最高效的(畢竟是JDK原生的),但是是序列化的結果字符串是最長 的。JSON由於其數據格式的緊湊性,序列化的長度是最小的,時間比前者要多一些。而OxmSerialiabler在時間上看是最長的(當時和使用具體 的Marshaller有關)。所以個人的選擇是傾向使用JacksonJsonRedisSerializer作為POJO的序列器。
