|
Spring-data-redis為spring-data模塊中對redis的支持部分,簡稱為“SDR”,提供了基于jedis客戶端API的高度封裝以及與spring容器的整合,事實上jedis客戶端已經(jīng)足夠簡單和輕量級,而spring-data-redis反而具有“過度設(shè)計”的嫌疑。
jedis客戶端在編程實施方面存在如下不足:
1) connection管理缺乏自動化,connection-pool的設(shè)計缺少必要的容器支持。
2) 數(shù)據(jù)操作需要關(guān)注“序列化”/“反序列化”,因為jedis的客戶端API接受的數(shù)據(jù)類型為string和byte,對結(jié)構(gòu)化數(shù)據(jù)(json,xml,pojo等)操作需要額外的支持。
3) 事務(wù)操作純粹為硬編碼
4) pub/sub功能,缺乏必要的設(shè)計模式支持,對于開發(fā)者而言需要關(guān)注的太多。
不過jedis與spring整合,也是非常的簡單,參見“jedis連接池實例”.
一. spring-data-redis針對jedis提供了如下功能:
1. 連接池自動管理,提供了一個高度封裝的“RedisTemplate”類
2. 針對jedis客戶端中大量api進行了歸類封裝,將同一類型操作封裝為operation接口
3. 提供了對key的“bound”(綁定)便捷化操作API,可以通過bound封裝指定的key,然后進行一系列的操作而無須“顯式”的再次指定Key,即BoundKeyOperations:
- BoundValueOperations
- BoundSetOperations
- BoundListOperations
- BoundSetOperations
- BoundHashOperations
4. 將事務(wù)操作封裝,有容器控制。
5. 針對數(shù)據(jù)的“序列化/反序列化”,提供了多種可選擇策略(RedisSerializer)
- JdkSerializationRedisSerializer:POJO對象的存取場景,使用JDK本身序列化機制,將pojo類通過ObjectInputStream/ObjectOutputStream進行序列化操作,最終redis-server中將存儲字節(jié)序列。是目前最常用的序列化策略。
- StringRedisSerializer:Key或者value為字符串的場景,根據(jù)指定的charset對數(shù)據(jù)的字節(jié)序列編碼成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封裝。是最輕量級和高效的策略。
- JacksonJsonRedisSerializer:jackson-json工具提供了javabean與json之間的轉(zhuǎn)換能力,可以將pojo實例序列化成json格式存儲在redis中,也可以將json格式的數(shù)據(jù)轉(zhuǎn)換成pojo實例。因為jackson工具在序列化和反序列化時,需要明確指定Class類型,因此此策略封裝起來稍微復(fù)雜。【需要jackson-mapper-asl工具支持】
- OxmSerializer:提供了將javabean與xml之間的轉(zhuǎn)換能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存儲的數(shù)據(jù)將是xml工具。不過使用此策略,編程將會有些難度,而且效率最低;不建議使用?!拘枰猻pring-oxm模塊的支持】
針對“序列化和發(fā)序列化”中JdkSerializationRedisSerializer和StringRedisSerializer是最基礎(chǔ)的策略,原則上,我們可以將數(shù)據(jù)存儲為任何格式以便應(yīng)用程序存取和解析(其中應(yīng)用包括app,hadoop等其他工具),不過在設(shè)計時仍然不推薦直接使用“JacksonJsonRedisSerializer”和“OxmSerializer”,因為無論是json還是xml,他們本身仍然是String。
如果你的數(shù)據(jù)需要被第三方工具解析,那么數(shù)據(jù)應(yīng)該使用StringRedisSerializer而不是JdkSerializationRedisSerializer。
如果你的數(shù)據(jù)格式必須為json或者xml,那么在編程級別,在redisTemplate配置中仍然使用StringRedisSerializer,在存儲之前或者讀取之后,使用“SerializationUtils”工具轉(zhuǎn)換轉(zhuǎn)換成json或者xml,請參見下文實例。
6. 基于設(shè)計模式,和JMS開發(fā)思路,將pub/sub的API設(shè)計進行了封裝,使開發(fā)更加便捷。
7.spring-data-redis中,并沒有對sharding提供良好的封裝,如果你的架構(gòu)是基于sharding,那么你需要自己去實現(xiàn),這也是sdr和jedis相比,唯一缺少的特性。
二.簡單實例:
1) spring配置:
- <beans xmlns="http://www./schema/beans"
- xmlns:xsi="http://www./2001/XMLSchema-instance"
- xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans.xsd" default-autowire="byName">
- <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
- <property name="maxActive" value="32"></property>
- <property name="maxIdle" value="6"></property>
- <property name="maxWait" value="15000"></property>
- <property name="minEvictableIdleTimeMillis" value="300000"></property>
- <property name="numTestsPerEvictionRun" value="3"></property>
- <property name="timeBetweenEvictionRunsMillis" value="60000"></property>
- <property name="whenExhaustedAction" value="1"></property>
- </bean>
- <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
- <property name="poolConfig" ref="jedisPoolConfig"></property>
- <property name="hostName" value="127.0.0.1"></property>
- <property name="port" value="6379"></property>
- <property name="password" value="0123456"></property>
- <property name="timeout" value="15000"></property>
- <property name="usePool" value="true"></property>
- </bean>
- <bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
- <property name="connectionFactory" ref="jedisConnectionFactory"></property>
- <property name="keySerializer">
- <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
- </property>
- <property name="valueSerializer">
- <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
- </property>
- </bean>
- </beans>
2) 程序?qū)嵗?/p>
- public class SpringDataRedisTestMain {
-
- /**
- * @param args
- */
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis-beans.xml");
- RedisTemplate redisTemplate = (RedisTemplate)context.getBean("jedisTemplate");
- //其中key采取了StringRedisSerializer
- //其中value采取JdkSerializationRedisSerializer
- ValueOperations<String, User> valueOper = redisTemplate.opsForValue();
- User u1 = new User("zhangsan",12);
- User u2 = new User("lisi",25);
- valueOper.set("u:u1", u1);
- valueOper.set("u:u2", u2);
- System.out.println(valueOper.get("u:u1").getName());
- System.out.println(valueOper.get("u:u2").getName());
- }
-
- /**
- * 如果使用jdk序列化方式,bean必須實現(xiàn)Serializable,且提供getter/setter方法
- * @author qing
- *
- */
- static class User implements Serializable{
-
- /**
- *
- */
- private static final long serialVersionUID = -3766780183428993793L;
- private String name;
- private Date created;
- private int age;
- public User(){}
- public User(String name,int age){
- this.name = name;
- this.age = age;
- this.created = new Date();
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Date getCreated() {
- return created;
- }
- public void setCreated(Date created) {
- this.created = created;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
-
- }
-
- }
3) RedisTemplate:
如果你使用過jedisPool連接池,在數(shù)據(jù)操作之前,你需要pool.getResource()即從連接池中獲取“鏈接資源”(Jedis),在操作之后,你需要(必須)調(diào)用pool.returnResource()將資源歸還個連接池。但是,spring-data-redis中,我們似乎并沒有直接操作pool,那么spring是如何做到pool管理的呢??一句話:spring的“看門絕技”--callback。
- public <T> T execute(RedisCallback<T> action):這個方法是redisTemplate中執(zhí)行操作的底層方法,任何基于redisTemplate之上的調(diào)用(比如,valueOperations)最終都會被封裝成RedisCallback,redisTemplate在execute方法中將會直接使用jedis客戶端API進行與server通信,而且在如果使用了連接池,則會在操作之后執(zhí)行returnSource。
其他實例請參考如下鏈接:
1) serializer實例
2) operation實例
3) pub/sub實例
|