Spring之Redis訪問(Spring-data-redis)
Spring-data-redis,是spring-data框架中,比較常用的,基於key-value鍵值對的資料持久層框架。Spring-data-redis,是一個基於Template模板開發的資料訪問層框架。都是基於配置+template方法呼叫,實現redis資料CRUD操作的。
沒有Spring-data-redis的時候,使用jedis-client來實現redis的訪問。需要自己控制jedis中的具體邏輯,實現redis資料的CURD操作。
spring-data框架中的每個子模組其版本未必一致,畢竟對應不同資料服務的訪問層框架,更新時間和週期是不同的。在本案例中,使用的spring-data-redis版本為1.8.14。spring-data-redis框架的執行需要jackson元件的輔助,建議匯入jackson版本為2.7+(對應當前環境中的spring-data-redis版本)。
包依賴:
<!-- spring-data-redis核心 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.8.14.RELEASE</version> </dependency> <!-- redis-client核心 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <!-- spring-data-redis做資料轉換使用的輔助外掛 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency>
全域性配置applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置讀取properties檔案的工具類 --> <context:property-placeholder location="classpath:redis/redis.properties"/> <!-- Jedis連線池,高效連線 value配置來自檔案redis.properties--> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.pool.maxTotal}"/> <property name="maxIdle" value="${redis.pool.maxIdle}"/> <property name="minIdle" value="${redis.pool.minIdle}"/> </bean> <!-- redis叢集配置 --> <bean id="redisClusterConfig" class="org.springframework.data.redis.connection.RedisClusterConfiguration"> <constructor-arg name="clusterNodes"> <list> <value>192.168.2.124:7001</value> <value>192.168.2.124:7002</value> <value>192.168.2.124:7003</value> <value>192.168.2.124:7004</value> <value>192.168.2.124:7005</value> <value>192.168.2.124:7006</value> </list> </constructor-arg> </bean> <!-- Jedis的連線工廠,不可缺少的。是用於構建連線物件jedis的。 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- 單機版訪問配置 --> <property name="hostName" value="${redis.conn.hostName}"/> <property name="port" value="${redis.conn.port}"/> <property name="poolConfig" ref="poolConfig"/> <!-- 叢集版訪問配置 --> <!-- <constructor-arg name="clusterConfig" ref="redisClusterConfig" /> <constructor-arg name="poolConfig" ref="poolConfig" /> --> </bean> <!-- Redis模板物件,類似JDBCTemplate。模板方法模式開發的程式碼。RedisTemplate中定義了若干的方法,用於實現資料的CRUD操作。 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> <!-- 序列化器:能夠把我們儲存的key與value做序列化處理的物件,是一個類似於converter的工具。 可以實現傳入的java物件->redis可以識別的資料型別。 如:字串。 預設的Serializer是StringRedisSerializer。 設定預設的序列化器是字串序列化器,原因是redis可以儲存的資料只有字串和位元組陣列。 一般來說,我們程式碼中操作的資料物件都是java物件。 如果程式碼中,使用的資料載體就是字串物件,那麼使用Jackson2JsonRedisSerializer來做序列化器是否會有問題? 如果jackson外掛的版本不合適,有錯誤隱患的話,可能將字串資料轉換為json字串 -> {chars:[], bytes:[]} 使用StringRedisSerializer就沒有這個問題。不處理字串轉換的。認為程式碼中操作的key和value都是字串。 --> <!-- 配置預設的序列化器 --> <!-- keySerializer、valueSerializer 配置Redis中的String型別key與value的序列化器 --> <!-- HashKeySerializer、HashValueSerializer 配置Redis中的Hash型別key與value的序列化器 --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> </bean> </beans>
Redis資料庫連線配置:redis.properties
redis.pool.maxTotal=20 redis.pool.maxIdle=10 redis.pool.minIdle=5 redis.conn.hostName=127.0.0.1 redis.conn.port=6379
測試類:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:redis/applicationContext.xml") public class RedisTest { @Autowired private RedisTemplate<String, Object> redisTemplate; /** * 新增鍵值對 - 字串型別 * redisTemplate中,提供了若干的Operations,每一個Operations對應一個Redis中的資料型別。 * 如:ValueOperations - 字串型別。 HashOperations - hash型別。 */ @Test public void test1(){ ValueOperations<String, Object> ops = this.redisTemplate.opsForValue(); ops.set("key", "test"); } /** * 獲取redis中的資料 */ @Test public void test2(){ String str = (String)this.redisTemplate.opsForValue().get("key"); System.out.println(str); // 新增/更新資料,並設定有效期。 // this.redisTemplate.opsForValue().set("key", "test", 10L, TimeUnit.SECONDS); // 設定資料有效期。 this.redisTemplate.expire("key", 10, TimeUnit.SECONDS); } /** * 新增Users * 將java物件,儲存到redis中,可以使用兩種儲存方式。 * 1 - 使用JDK提供的Serializable,實現物件序列化。 * 改變valueSerilizer的序列化器。JdkSerializationRedisSerializer * 用JDKSerializationRedisSerializer做序列化,有不好的地方。 * JDKSerialization序列化結果太長。佔用更多的位元組空間。進行序列化和反序列化的效率較低。 * 並且物件必須實現序列化介面,如public class Users implements Serializable */ @Test public void test3(){ Users users = new Users(); users.setUserage(30); users.setUserid(1); users.setUsername("張三"); //更換序列化器,通過API來更換序列化器,好處是有針對性。需要什麼序列化器就提供什麼序列化器。預設都使用StringRedisSerializer this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); this.redisTemplate.opsForValue().set("users", users); } /** * 獲取Users * */ @Test public void test4(){ //更換序列化器 this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); Users users = (Users)this.redisTemplate.opsForValue().get("users"); System.out.println(users); } /** * 新增Users JSON格式 * JSON資料,人機皆可使用。 * JSON資料佔用的儲存空間小,且和java物件的轉換效率高。 * 缺陷 - 不能描述雙向關係。如果使用json來描述雙向關聯關係,則會出現無限巢狀,是一個死迴圈。會有記憶體溢位錯誤, OutOfMemeryError * class A{ B b; } * class B{ A a; } * A a = new A(); * json - { .... , b : { ... , a : { ...., b : { ...., a : { }}}}} */ @Test public void test5(){ Users users = new Users(); users.setUserage(30); users.setUserid(2); users.setUsername("李四"); this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Users>(Users.class)); this.redisTemplate.opsForValue().set("usersjson", users); } /** * 獲取Uesrs JSON格式 */ @Test public void test6(){ this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Users>(Users.class)); Users users = (Users)this.redisTemplate.opsForValue().get("usersjson"); System.out.println(users); } /** * 常用API */ @Test public void test7(){ // 設定有效期 this.redisTemplate.expire("usersjson", 300, TimeUnit.SECONDS); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // 查詢有效期 long expire = this.redisTemplate.getExpire("usersjson"); System.out.println("expire = " + expire); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } // 刪除有效期 this.redisTemplate.persist("usersjson"); } }
User實體類:
@Entitypublic class Users implements Serializable{ private Integer userid;private String username;private Integer userage;
public Users(String username, Integer userage){ this.username = username; this.userage = userage; } public Integer getUserid() { return userid; } public void setUserid(Integer userid) { this.userid = userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getUserage() { return userage; } public void setUserage(Integer userage) { this.userage = userage; } @Override public String toString() { return "Users [userid=" + userid + ", username=" + username + ", userage=" + userage + "]"; } }
知識補充(序列化:Serialize)
功能 - 將記憶體中的java物件與位元組陣列做雙向轉換。
作用 - 只要涉及到IO操作的時候,IO中可以傳遞的資料只有位元組,java物件是不能通過IO傳遞的。所以,需要使用IO傳遞java物件的時候,必須涉及到序列化和反序列化。
序列化ID - 是用於區分位元組資訊和java型別直接關係的一個基礎資料。如果設計上,不怕麻煩,建議給不同的型別,定義儘可能不同的序列化ID,可以提升序列化和反序列化的效率。但是,對效率的提升不是很明顯。
序列化ID,只有一個要求,就是一樣的型別的物件,必須使用相同值的序列化ID。
一般開發的時候,序列化ID都設定為-1/1。