spring整合redis

redis概述

參考:《spring boot 整合redis之緩存》之redis概述章節;

  • spring整合reids
  • 項目中使用redis做緩存管理
  • 注意事項(問題及解決方案)

項目源碼地址:
碼雲地址:https://gitee.com/wyait/project.git
github地址:https://github.com/wyait/project.git

spring 整合redis

導入依賴

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.7.5.RELEASE</version>
</dependency>

配置文件

redis.properties

redis相關參數文件:

#ip地址  
redis.host.ip=127.0.0.1
#端口號  
redis.port=6379  
#如果有密碼  
redis.password=  
#客戶端超時時間單位是毫秒 默認是2000  
redis.timeout=3000  

#最大空閒數  
redis.maxIdle=6  
#連接池的最大數據庫連接數。設爲0表示無限制,如果是jedis 2.4以後用redis.maxTotal  
#redis.maxActive=600  
#控制一個pool可分配多少個jedis實例,用來替換上面的redis.maxActive,如果是jedis 2.4以後用該屬性  
redis.maxTotal=20  
#最大建立連接等待時間。如果超過此時間將接到異常。設爲-1表示無限制。  
redis.maxWaitMillis=3000  
#連接的最小空閒時間 默認1800000毫秒(30分鐘)  
redis.minEvictableIdleTimeMillis=300000  
#每次釋放連接的最大數目,默認3  
redis.numTestsPerEvictionRun=4  
#逐出掃描的時間間隔(毫秒) 如果爲負數,則不運行逐出線程, 默認-1  
redis.timeBetweenEvictionRunsMillis=30000  

applicationContext-redis.xml

spring整合redis配置文件:

    <!--1,如果你有多個數據源需要通過<context:property-placeholder管理,且不願意放在一個配置文件裏,那麼一定要加上ignore-unresolvable=“true" -->
    <context:property-placeholder location="classpath:redis.properties"
        ignore-unresolvable="true" />

    <!--2,注意新版本2.3以後,JedisPoolConfig的property name,不是maxActive而是maxTotal,而且沒有maxWait屬性,建議看一下Jedis源碼或百度。 -->
    <!-- redis連接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空閒數 -->
        <property name="maxIdle" value="${redis.maxIdle}" />
        <!--連接池的最大數據庫連接數 -->
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!--最大建立連接等待時間 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!--逐出連接的最小空閒時間 默認1800000毫秒(30分鐘) -->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
        <!--每次逐出檢查時 逐出的最大數目 如果爲負數就是 : 1/abs(n), 默認3 -->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
        <!--逐出掃描的時間間隔(毫秒) 如果爲負數,則不運行逐出線程, 默認-1 -->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
    </bean>

    <!--redis連接工廠 -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        destroy-method="destroy">
        <property name="poolConfig" ref="jedisPoolConfig"></property>
        <!--IP地址 -->
        <property name="hostName" value="${redis.host.ip}"></property>
        <!--端口號 -->
        <property name="port" value="${redis.port}"></property>
        <!--如果Redis設置有密碼 -->
        <!-- <property name="password" value="${redis.password}" /> -->
        <!--客戶端超時時間單位是毫秒 -->
        <property name="timeout" value="${redis.timeout}"></property>
    </bean>

    <!-- redis操作模板,這裏採用儘量面向對象的模板 -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <!-- 指定redis中key-value的序列化方式(此處省略) -->
    </bean>

    <!--redis工具類 (也可以通過註解的方式注入) -->
    <bean id="redisUtil" class="com.spring.redis.utils.RedisUtil">
        <property name="redisTemplate" ref="redisTemplate" />
    </bean>

RedisUtils工具類

代碼片段:

package com.spring.redis.util;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

/** 
 * 
 * @項目名稱:common
 * @類名稱:RedisUtil
 * @類描述:基於spring和redis的redisTemplate工具類;
 * @創建人:wyait
 * @創建時間:2017年12月8日 下午3:32:38 
 * @version:V1.0
 */
// @Component
public class RedisUtil {
    // 通過構造方法注入
    // @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /*
     * 如果使用註解注入RedisTemplate對象,則不需要該setter方法
     */
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /** 
     * String類型緩存獲取 
     * @param key 鍵 
     * @return 值 
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /** 
     * String類型緩存保存 
     * @param key 鍵 
     * @param value 值 
     * @return true:成功;false:失敗 
     */
    public boolean set(String key, Object value) {
        try {
            if (StringUtils.isNotEmpty(key) && null != value) {
                redisTemplate.opsForValue().set(key, value);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

   // ... ...

}

測試

  • 訪問:http://127.0.0.1:8063/add
    結果:hello world
    查看redis桌面工具,已有數據,雖然看不懂。。。如圖:
    image
    亂碼的原因是:RedisTemplate默認的使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializer這個類進行序列化導致的,如果單獨指定了redis的key-value序列化方式,就不會出現亂碼的情況。 (源碼中已解決亂碼問題)

訪問:http://127.0.0.1:8063/get
結果:aaa

Caused by: redis.clients.jedis.exceptions.JedisDataException: WRONGTYPE Operation against a key holding the wrong kind of value
    at redis.clients.jedis.Protocol.processError(Protocol.java:127)

因爲redis數據庫中已經存在了相同的key, 而且key對應的值類型並不是HashMap或Object;再調用setHash時,就會拋出此錯誤。

解決:更改key的值;

訪問:http://127.0.0.1:8063/getHash
結果:{"user":{"id":1,"age":11,"name":"李四"}}

使用redis API做緩存管理

這裏用RedisUtils工具類實現數據緩存;
使用緩存註解,請參考:《spring boot 整合redis之緩存》之redis緩存管理;

項目中使用redis

項目中查詢業務做緩存,必須在不影響正常業務的情況下,對數據進行緩存;具體做法:

  • 1,查mysql數據庫和redis緩存結合使用;
    查詢業務:先查詢redis緩存,有就返回數據;沒有,直接查詢mysql數據庫;
    代碼片段:
// 從redis中緩存中獲取詳情數據
String redisString = "";
try {
    //避免redis異常影響到正常業務
    redisString=this.redisUtil.get("aaa:bbb");
} catch (Exception e) {
    //TODO
    LOGGER.error("redis get error");
}
if (StringUtils.isEmpty(redisString)) {
    //查詢數據庫
    //TODO
}

更新業務:先更新mysql數據庫中的數據,更新成功;更新redis緩存中的數據;比如:添加數據,先添加到mysql中;在添加一條數據在redis中;
代碼片段:

//TODO
//更新數據OK
try {
    //避免redis異常影響到正常業務
    //更新redis中數據,並指定保存時間
    redisString=this.redisUtil.set("aaa:bbb","值",3600);
} catch (Exception e) {
    //TODO
    LOGGER.error("redis set error");
}
  • 2,對於redis操作,進行try...catch...處理;保證應用程序的可用性,如上面兩段代碼;

redis中key使用策略

Redis上踩過的一些坑-美團:http://blog.csdn.net/chenleixing/article/details/50530419
redis內存使用優化:http://carlosfu.iteye.com/blog/2254572

(1) 使用Redis字符串數據結構, userId爲key, weiboCount作爲Value
(2) 使用Redis哈希結構,hashkey只有一個, key="allUserWeiboCount",field=userId,fieldValue= weiboCount
(3) 使用Redis哈希結構, hashkey爲多個, key=userId/100, field=userId%100, fieldValue= weiboCount
前兩種比較容易理解,第三種方案解釋一下:每個hashKey存放100個hash-kv,field=userId%100。。。

實際使用根據具體的業務而定,數據量沒那麼大的情況下,不用考慮內存優化的問題;

另外在使用String類型的key的時候,推薦用:

aaa:bbb

這種格式,這樣在redis桌面工具中查看方便直觀,針對key中有:的情況,redis桌面工具會對其進行統一分類,方便查看!
image

注意

spring data redis會有版本衝突問題,導致啓動異常;

異常情況:

aused by: java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.<init>(JdkSerializationRedisSerializer.java:53)
  • 原因:
    spring-data-redis版本:1.7.2.RELEASE ,不兼容spring 版本:4.1.3.RELEASE
  • 解決方案:
    spring data redis版本不能高於:1.7.1.RELEASE

穩定版本:

spring版本:4.2.3.RELEASE - 4.3.9.RELEASE
spring-data-redis版本:1.7.2.RELEASE - 1.7.11.RELEASE
jedis版本:2.9.0

項目源碼地址:
碼雲地址:https://gitee.com/wyait/project.git
github地址:https://github.com/wyait/project.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章