Redis實戰之徵服 Redis + Jedis + Spring (一)

Redis + Jedis + Spring (一)—— 配置&常規操做(GET SET DEL)接着須要快速的調研下基於spring框架下的Redis操做。java

相關連接:redis

Redis實戰spring

Redis實戰之Redis + Jedismongodb

Redis實戰之徵服 Redis + Jedis + Spring (一)app

Redis實戰之徵服 Redis + Jedis + Spring (二)框架

Redis實戰之徵服 Redis + Jedis + Spring (三)dom

 

前文有述,Spring提供了對於Redis的專門支持:spring-data-redis。此外,相似的還有:ide


 

我想大部分人對spring-data-Hadoopspring-data-MongoDBspring-data-redis以及spring-data-jpa表示關注。oop

1、簡述

spring把專門的數據操做獨立封裝在spring-data系列中,spring-data-redis天然是針對Redis的獨立封裝了。ui

當前版本1.0.1,主要是將jedisjredisrjc以及srpRedis Client進行了封裝,同時支持事務。已經讓我垂涎欲滴了。固然,當前版本不支持Sharding。例如,前文曾經經過Jedis經過Client配置,實現一致性哈希,達到Sharding的目的。再一點,若是你早在spring1.x寫過SpringJdbc的話,如今會以爲似曾相識。

 

在通過一番思想鬥爭後,我最終放棄了Jedis原生實現,擁抱spring-data-redis了。爲何?由於,我須要一個有事務機制的框架,一個不須要顯式調用對象池操做的框架。這些spring-data-redis都解決了。至於Sharding,當前數據量要求還不大,期待Redis 3.0吧。

 

2、配置

對象池配置:

 

Xml代碼   
  1. <bean  
  2.         id="jedisPoolConfig"  
  3.         class="redis.clients.jedis.JedisPoolConfig"  
  4.     >  
  5.         <property  
  6.             name="maxActive"  
  7.             value="${redis.pool.maxActive}" />  
  8.         <property  
  9.             name="maxIdle"  
  10.             value="${redis.pool.maxIdle}" />  
  11.         <property  
  12.             name="maxWait"  
  13.             value="${redis.pool.maxWait}" />  
  14.         <property  
  15.             name="testOnBorrow"  
  16.             value="${redis.pool.testOnBorrow}" />  
  17.     </bean>  
[xml]  view plain  copy
  1. <bean  
  2.         id="jedisPoolConfig"  
  3.         class="redis.clients.jedis.JedisPoolConfig"  
  4.     >  
  5.         <property  
  6.             name="maxActive"  
  7.             value="${redis.pool.maxActive}" />  
  8.         <property  
  9.             name="maxIdle"  
  10.             value="${redis.pool.maxIdle}" />  
  11.         <property  
  12.             name="maxWait"  
  13.             value="${redis.pool.maxWait}" />  
  14.         <property  
  15.             name="testOnBorrow"  
  16.             value="${redis.pool.testOnBorrow}" />  
  17.     </bean>  

 

 

 

工廠實現:

 

Xml代碼   
  1. <bean  
  2.     id="jedisConnectionFactory"  
  3.     class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
  4. >  
  5.     <property  
  6.         name="hostName"  
  7.         value="${redis.ip}" />  
  8.     <property  
  9.         name="port"  
  10.         value="${redis.port}" />  
  11.     <property  
  12.         name="poolConfig"  
  13.         ref="jedisPoolConfig" />  
  14. </bean>  
[xml]  view plain  copy
  1. <bean  
  2.     id="jedisConnectionFactory"  
  3.     class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
  4. >  
  5.     <property  
  6.         name="hostName"  
  7.         value="${redis.ip}" />  
  8.     <property  
  9.         name="port"  
  10.         value="${redis.port}" />  
  11.     <property  
  12.         name="poolConfig"  
  13.         ref="jedisPoolConfig" />  
  14. </bean>  

 

 

 

模板類:

 

Xml代碼   
  1. <bean  
  2.         class="org.springframework.data.redis.core.RedisTemplate"  
  3.         p:connection-factory-ref="jedisConnectionFactory" />  
[xml]  view plain  copy
  1. <bean  
  2.         class="org.springframework.data.redis.core.RedisTemplate"  
  3.         p:connection-factory-ref="jedisConnectionFactory" />  

 

 

 

是否是很像配置一個JdbcTemplate?其實就這麼簡單。

redis.properties配置以下:

 

Properties代碼   
  1. #最大分配的對象數  
  2. redis.pool.maxActive=1024  
  3. #最大可以保持idel狀態的對象數  
  4. redis.pool.maxIdle=200  
  5. #當池內沒有返回對象時,最大等待時間  
  6. redis.pool.maxWait=1000  
  7. #當調用borrow Object方法時,是否進行有效性檢查  
  8. redis.pool.testOnBorrow=true  
  9.   
  10. #IP  
  11. redis.ip=10.11.20.140  
  12. #Port  
  13. redis.port=6379  

 

 

 

當前只能用一個節點,期待Redis 3.0,Sharding吧!

 

3、GET、SET、DEL操做

Redis初來乍練,目前也就是用Memcached多些,只會這些基本的操做,在這裏獻醜了!

 

假定作一個UserDao:

 

Java代碼   
  1. public interface UserDao {  
  2.     /** 
  3.      * @param uid 
  4.      * @param address 
  5.      */  
  6.     void save(User user);  
  7.   
  8.     /** 
  9.      * @param uid 
  10.      * @return  
  11.      */  
  12.     User read(String uid);  
  13.   
  14.     /** 
  15.      * @param uid 
  16.      */  
  17.     void delete(String uid);  
  18. }  
[java]  view plain  copy
  1. public interface UserDao {  
  2.     /** 
  3.      * @param uid 
  4.      * @param address 
  5.      */  
  6.     void save(User user);  
  7.   
  8.     /** 
  9.      * @param uid 
  10.      * @return 
  11.      */  
  12.     User read(String uid);  
  13.   
  14.     /** 
  15.      * @param uid 
  16.      */  
  17.     void delete(String uid);  
  18. }  

 

 

 

User對象就這麼兩個屬性:

 

Java代碼   
  1. public class User implements Serializable {  
  2.   
  3.     private static final long serialVersionUID = -1267719235225203410L;  
  4.   
  5.     private String uid;  
  6.   
  7.     private String address;  
  8. }  
[java]  view plain  copy
  1. public class User implements Serializable {  
  2.   
  3.     private static final long serialVersionUID = -1267719235225203410L;  
  4.   
  5.     private String uid;  
  6.   
  7.     private String address;  
  8. }  

 

 

 

實現這三個方法須要獲得RedisTemplate的支持:

 

Java代碼   
  1. @Autowired  
  2. private RedisTemplate<Serializable, Serializable> redisTemplate;  
[java]  view plain  copy
  1. @Autowired  
  2. private RedisTemplate<Serializable, Serializable> redisTemplate;  

 

 爲何用序列化泛型?我存的數據都是可序列化的內容。還有更多爲何?其實我也解答不了不少,邊練邊學,我弄通了必定告訴你!

 

 

1.保存-SET

 

作一個保存造做,使用RedisSET命令:

 

Java代碼   
  1. @Override  
  2. public void save(final User user) {  
  3.     redisTemplate.execute(new RedisCallback<Object>() {  
  4.         @Override  
  5.         public Object doInRedis(RedisConnection connection)  
  6.                 throws DataAccessException {  
  7.             connection.set(  
  8.                     redisTemplate.getStringSerializer().serialize(  
  9.                             "user.uid." + user.getUid()),  
  10.                     redisTemplate.getStringSerializer().serialize(  
  11.                             user.getAddress()));  
  12.             return null;  
  13.         }  
  14.     });  
  15. }  
[java]  view plain  copy
  1. @Override  
  2. public void save(final User user) {  
  3.     redisTemplate.execute(new RedisCallback<Object>() {  
  4.         @Override  
  5.         public Object doInRedis(RedisConnection connection)  
  6.                 throws DataAccessException {  
  7.             connection.set(  
  8.                     redisTemplate.getStringSerializer().serialize(  
  9.                             "user.uid." + user.getUid()),  
  10.                     redisTemplate.getStringSerializer().serialize(  
  11.                             user.getAddress()));  
  12.             return null;  
  13.         }  
  14.     });  
  15. }  

 

 這裏是經過模板類,實現方法回調。在spring框架下,能夠方便的控制事務,若是你研究過spring的dao源代碼,對此必定熟悉。

 

 

  1. 傳入參數,須要final標識,禁止方法內修改。
  2. 調用RedisConnectionset方法實現RedisSET命令。
  3. 無論是Key,仍是Value都須要進行Serialize
  4. 序列化操做,最好使用RedisTemplate提供的Serializer來完成。

 

這跟當年的SpringJdbcTemplate有那麼一拼!

 

2.獲取-GET

想要將對象從Redis中取出來,就麻煩一些,須要序列化key,最好判斷下這個key是否存在,避免無用功。若是鍵值存在,須要對數據反序列化。

 

Java代碼   
  1. @Override  
  2. public User read(final String uid) {  
  3.     return redisTemplate.execute(new RedisCallback<User>() {  
  4.         @Override  
  5.         public User doInRedis(RedisConnection connection)  
  6.                 throws DataAccessException {  
  7.             byte[] key = redisTemplate.getStringSerializer().serialize(  
  8.                     "user.uid." + uid);  
  9.             if (connection.exists(key)) {  
  10.                 byte[] value = connection.get(key);  
  11.                 String address = redisTemplate.getStringSerializer()  
  12.                         .deserialize(value);  
  13.                 User user = new User();  
  14.                 user.setAddress(address);  
  15.                 user.setUid(uid);  
  16.                 return user;  
  17.             }  
  18.             return null;  
  19.         }  
  20.     });  
  21. }  
[java]  view plain  copy
  1. @Override  
  2. public User read(final String uid) {  
  3.     return redisTemplate.execute(new RedisCallback<User>() {  
  4.         @Override  
  5.         public User doInRedis(RedisConnection connection)  
  6.                 throws DataAccessException {  
  7.             byte[] key = redisTemplate.getStringSerializer().serialize(  
  8.                     "user.uid." + uid);  
  9.             if (connection.exists(key)) {  
  10.                 byte[] value = connection.get(key);  
  11.                 String address = redisTemplate.getStringSerializer()  
  12.                         .deserialize(value);  
  13.                 User user = new User();  
  14.                 user.setAddress(address);  
  15.                 user.setUid(uid);  
  16.                 return user;  
  17.             }  
  18.             return null;  
  19.         }  
  20.     });  
  21. }  

 

 當年寫SpringJdbc的時候,就是這樣一個字段一個字段拼裝的,甭提多累人。好吧,用Spring-Data-Redis,又讓我回歸了!

 

 

  1. 記得使用泛型,如RedisCallback<User>()
  2. 使用同一的序列化/反序列化Serializer
  3. 建議使用connection.exists(key)判別鍵值是否存在,避免無用功

 

3.刪除-DEL

刪除,就簡單點,不過也須要這樣折騰一會:

 

Java代碼   
  1. @Override  
  2. public void delete(final String uid) {  
  3.     redisTemplate.execute(new RedisCallback<Object>() {  
  4.         public Object doInRedis(RedisConnection connection) {  
  5.             connection.del(redisTemplate.getStringSerializer().serialize(  
  6.                     "user.uid." + uid));  
  7.             return null;  
  8.         }  
  9.     });  
  10. }  
[java]  view plain  copy
  1. @Override  
  2. public void delete(final String uid) {  
  3.     redisTemplate.execute(new RedisCallback<Object>() {  
  4.         public Object doInRedis(RedisConnection connection) {  
  5.             connection.del(redisTemplate.getStringSerializer().serialize(  
  6.                     "user.uid." + uid));  
  7.             return null;  
  8.         }  
  9.     });  
  10. }  

 

 

作個TestCase,暫時夠我用了!

 

4. TestCase

 

 

Java代碼   
  1. import static org.junit.Assert.*;  
  2. import org.junit.Before;  
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6. import org.zlex.redis.dao.UserDao;  
  7. import org.zlex.redis.domain.User;  
  8.   
  9. public class UserDaoTest {  
  10.     private ApplicationContext app;  
  11.     private UserDao userDao;  
  12.   
  13.     @Before  
  14.     public void before() throws Exception {  
  15.         app = new ClassPathXmlApplicationContext("applicationContext.xml");  
  16.         userDao = (UserDao) app.getBean("userDao");  
  17.     }  
  18.   
  19.     @Test  
  20.     public void crud() {  
  21.         // -------------- Create ---------------  
  22.         String uid = "u123456";  
  23.         String address1 = "上海";  
  24.         User user = new User();  
  25.         user.setAddress(address1);  
  26.         user.setUid(uid);  
  27.         userDao.save(user);  
  28.   
  29.         // ---------------Read ---------------  
  30.         user = userDao.read(uid);  
  31.   
  32.         assertEquals(address1, user.getAddress());  
  33.   
  34.         // --------------Update ------------  
  35.         String address2 = "北京";  
  36.         user.setAddress(address2);  
  37.         userDao.save(user);  
  38.   
  39.         user = userDao.read(uid);  
  40.   
  41.         assertEquals(address2, user.getAddress());  
  42.   
  43.         // --------------Delete ------------  
  44.         userDao.delete(uid);  
  45.         user = userDao.read(uid);  
  46.         assertNull(user);  
  47.     }  
  48. }  
[java]  view plain  copy
  1. import static org.junit.Assert.*;  
  2. import org.junit.Before;  
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6. import org.zlex.redis.dao.UserDao;  
  7. import org.zlex.redis.domain.User;  
  8.   
  9. public class UserDaoTest {  
  10.     private ApplicationContext app;  
  11.     private UserDao userDao;  
  12.   
  13.     @Before  
  14.     public void before() throws Exception {  
  15.         app = new ClassPathXmlApplicationContext("applicationContext.xml");  
  16.         userDao = (UserDao) app.getBean("userDao");  
  17.     }  
  18.   
  19.     @Test  
  20.     public void crud() {  
  21.         // -------------- Create ---------------  
  22.         String uid = "u123456";  
  23.         String address1 = "上海";  
  24.         User user = new User();  
  25.         user.setAddress(address1);  
  26.         user.setUid(uid);  
  27.         userDao.save(user);  
  28.   
  29.         // ---------------Read ---------------  
  30.         user = userDao.read(uid);  
  31.   
  32.         assertEquals(address1, user.getAddress());  
  33.   
  34.         // --------------Update ------------  
  35.         String address2 = "北京";  
  36.         user.setAddress(address2);  
  37.         userDao.save(user);  
  38.   
  39.         user = userDao.read(uid);  
  40.   
  41.         assertEquals(address2, user.getAddress());  
  42.   
  43.         // --------------Delete ------------  
  44.         userDao.delete(uid);  
  45.         user = userDao.read(uid);  
  46.         assertNull(user);  
  47.     }  
  48. }  

 

 貌似少了update,也許之後操做Hash時,會用上。

 

看看控制檯得到了什麼: 

 

redis 127.0.0.1:6379> get user.uid.u123456
(nil)
redis 127.0.0.1:6379> get user.uid.u123456
"\xe5\x8c\x97\xe4\xba\xac"
redis 127.0.0.1:6379> get user.uid.u123456
"\xe4\xb8\x8a\xe6\xb5\xb7"
redis 127.0.0.1:6379> del user.uid.u123456
(integer) 1
redis 127.0.0.1:6379> get user.uid.u123456
(nil)
redis 127.0.0.1:6379> get user.uid.u123456
"\xe4\xb8\x8a\xe6\xb5\xb7"

 好吧,能夠開始用它來存點什麼了!

 

相關連接:

Redis實戰

Redis實戰之Redis + Jedis

Redis實戰之徵服 Redis + Jedis + Spring (一)

Redis實戰之徵服 Redis + Jedis + Spring (二)

Redis實戰之徵服 Redis + Jedis + Spring (三)

相關文章
相關標籤/搜索