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都是字符串。
         -->
        <!-- 配置默認的序列化器 -->
        <!-- keySerializervalueSerializer 配置Redis中的String類型key與value的序列化器 -->
        <!-- HashKeySerializerHashValueSerializer 配置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。


免責聲明!

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



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