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桌面工具,已有數據,雖然看不懂。。。如圖:
亂碼的原因是:RedisTemplate默認的使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializer這個類進行序列化導致的,如果單獨指定了redis的key-value序列化方式,就不會出現亂碼的情況。 (源碼中已解決亂碼問題)
訪問:http://127.0.0.1:8063/get
結果:aaa
- 訪問:http://127.0.0.1:8063/addHash ; 原代碼中key的值也是: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/addHash
結果:hello world
redis桌面工具中數據顯示:
訪問: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桌面工具會對其進行統一分類,方便查看!
注意
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