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


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

相關鏈接:

Redis實戰

Redis實戰之Redis + Jedis

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

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

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

 

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


 

我想大部分人對spring-data-hadoopspring-data-mongodbspring-data-redis以及spring-data-jpa表示關注。

一、簡述

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

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

 

在經過一番思想斗爭后,我最終放棄了Jedis原生實現,擁抱spring-data-redis了。為什么?因為,我需要一個有事務機制的框架,一個不需要顯式調用對象池操作的框架。這些spring-data-redis都解決了。至於Sharding,當前數據量要求還不大,期待Redis 3.0吧。

 

二、配置

對象池配置:

 

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>  
<bean
		id="jedisPoolConfig"
		class="redis.clients.jedis.JedisPoolConfig"
	>
		<property
			name="maxActive"
			value="${redis.pool.maxActive}" />
		<property
			name="maxIdle"
			value="${redis.pool.maxIdle}" />
		<property
			name="maxWait"
			value="${redis.pool.maxWait}" />
		<property
			name="testOnBorrow"
			value="${redis.pool.testOnBorrow}" />
	</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>  
	<bean
		id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
	>
		<property
			name="hostName"
			value="${redis.ip}" />
		<property
			name="port"
			value="${redis.port}" />
		<property
			name="poolConfig"
			ref="jedisPoolConfig" />
	</bean>

 

 

 

模板類:

 

Xml代碼  
  1. <bean  
  2.         class="org.springframework.data.redis.core.RedisTemplate"  
  3.         p:connection-factory-ref="jedisConnectionFactory" />  
<bean
		class="org.springframework.data.redis.core.RedisTemplate"
		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.pool.maxActive=1024
#最大能夠保持idel狀態的對象數
redis.pool.maxIdle=200
#當池內沒有返回對象時,最大等待時間
redis.pool.maxWait=1000
#當調用borrow Object方法時,是否進行有效性檢查
redis.pool.testOnBorrow=true

#IP
redis.ip=10.11.20.140
#Port
redis.port=6379

 

 

 

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

 

三、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. }  
public interface UserDao {
	/**
	 * @param uid
	 * @param address
	 */
	void save(User user);

	/**
	 * @param uid
	 * @return
	 */
	User read(String uid);

	/**
	 * @param uid
	 */
	void delete(String uid);
}

 

 

 

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. }  
public class User implements Serializable {

	private static final long serialVersionUID = -1267719235225203410L;

	private String uid;

	private String address;
}

 

 

 

實現這三個方法需要得到RedisTemplate的支持:

 

Java代碼  
  1. @Autowired  
  2. private RedisTemplate<Serializable, Serializable> redisTemplate;  
	@Autowired
	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. }  
	@Override
	public void save(final User user) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				connection.set(
						redisTemplate.getStringSerializer().serialize(
								"user.uid." + user.getUid()),
						redisTemplate.getStringSerializer().serialize(
								user.getAddress()));
				return null;
			}
		});
	}

 

 這里是通過模板類,實現方法回調。在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. }  
	@Override
	public User read(final String uid) {
		return redisTemplate.execute(new RedisCallback<User>() {
			@Override
			public User doInRedis(RedisConnection connection)
					throws DataAccessException {
				byte[] key = redisTemplate.getStringSerializer().serialize(
						"user.uid." + uid);
				if (connection.exists(key)) {
					byte[] value = connection.get(key);
					String address = redisTemplate.getStringSerializer()
							.deserialize(value);
					User user = new User();
					user.setAddress(address);
					user.setUid(uid);
					return user;
				}
				return null;
			}
		});
	}

 

 當年寫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. }  
	@Override
	public void delete(final String uid) {
		redisTemplate.execute(new RedisCallback<Object>() {
			public Object doInRedis(RedisConnection connection) {
				connection.del(redisTemplate.getStringSerializer().serialize(
						"user.uid." + uid));
				return null;
			}
		});
	}

 

 

做個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. }  
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.zlex.redis.dao.UserDao;
import org.zlex.redis.domain.User;

public class UserDaoTest {
	private ApplicationContext app;
	private UserDao userDao;

	@Before
	public void before() throws Exception {
		app = new ClassPathXmlApplicationContext("applicationContext.xml");
		userDao = (UserDao) app.getBean("userDao");
	}

	@Test
	public void crud() {
		// -------------- Create ---------------
		String uid = "u123456";
		String address1 = "上海";
		User user = new User();
		user.setAddress(address1);
		user.setUid(uid);
		userDao.save(user);

		// ---------------Read ---------------
		user = userDao.read(uid);

		assertEquals(address1, user.getAddress());

		// --------------Update ------------
		String address2 = "北京";
		user.setAddress(address2);
		userDao.save(user);

		user = userDao.read(uid);

		assertEquals(address2, user.getAddress());

		// --------------Delete ------------
		userDao.delete(uid);
		user = userDao.read(uid);
		assertNull(user);
	}
}

 

 貌似少了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 (三)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM