(一)SpringBoot中搭建Redis緩存
這篇文章講述如何在Springboot中搭建redis,按照以下步驟進行
1)、以下鏈接 是如何在window本地搭建redis進行測試
https://blog.csdn.net/qq_29434911/article/details/79876580
注意:在導入jedis-2.6.2.jar、spring-data-redis-1.4.2.RELEASE.jar 如果你下載的版本太低可能會提示版本有誤(解決方法只要重新下一個高版本就行了),我這個版本應該是沒錯的。之前
spring-data-redis-1.4.2.RELEASE.jar 我是下載1.0.0所以太低了。
2)在Springboot運用redis方法進行緩存操作
第一步:在pom.xml文件中配置redis
<!--redis配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId> <!-- 可以不需要加入版本號 -->
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.5.2</version>
</dependency>
第二步:初始化Redis連接池 ,操作redis
CacheKit.java:
package com.zcwl.redis;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;
public class CacheKit {
private static Logger logger = LoggerFactory.getLogger(CacheKit.class);
private List<JSONObject> resultList;
private static JedisPool pool;
/**
* 初始化Redis連接池
*/
private static void initializePool() {
//redisURL 與 redisPort 的配置文件
JedisPoolConfig config = new JedisPoolConfig();
//設置最大連接數(100個足夠用了,沒必要設置太大)
config.setMaxTotal(100);
//最大空閒連接數
config.setMaxIdle(10);
//獲取Jedis連接的最大等待時間(50秒)
config.setMaxWaitMillis(50 * 1000);
//在獲取Jedis連接時,自動檢驗連接是否可用
config.setTestOnBorrow(true);
//在將連接放回池中前,自動檢驗連接是否有效
config.setTestOnReturn(true);
//自動測試池中的空閒連接是否都是可用連接
config.setTestWhileIdle(true);
//創建連接池
//pool = new JedisPool(config, "120.88.166.244",6379); //連接阿里雲服務器上面的緩存(如果本地在使用地址,本地運行將會把本地緩存數據同步在線上緩存中)
pool = new JedisPool(config, "127.0.0.1",6379); //本地緩存(更新需要將這個註釋起來,解開上面地址)
}
/**
* 多線程環境同步初始化(保證項目中有且僅有一個連接池)
*/
private static synchronized void poolInit() {
if (null == pool) {
initializePool();
}
}
/**
* 獲取Jedis實例
*/
private static Jedis getJedis() {
if (null == pool) {
poolInit();
}
int timeoutCount = 0;
while (true) {
try {
if (null != pool) {
return pool.getResource();
}
} catch (Exception e) {
if (e instanceof JedisConnectionException) {
timeoutCount++;
logger.warn("getJedis timeoutCount={}", timeoutCount);
if (timeoutCount > 3) {
break;
}
} else {
/* logger.warn("jedisInfo ... NumActive=" + pool.getResource().get("")
+ ", NumIdle=" + pool.getNumIdle()
+ ", NumWaiters=" + pool.getNumWaiters()
+ ", isClosed=" + pool.isClosed()); */
logger.warn(pool.getResource()+"//"+pool);
logger.error("GetJedis error,", e);
break;
}
}
break;
}
return null;
}
/**
* 釋放Jedis資源
*
* @param jedis
*/
private static void returnResource(Jedis jedis) {
if (null != jedis) {
pool.returnResourceObject(jedis);
}
}
/**
* 絕對獲取方法(保證一定能夠使用可用的連接獲取到 目標數據)
* Jedis連接使用後放回
* @param key
* @return
*/
private String safeGet(String key) {
Jedis jedis = getJedis();
while (true) {
if (null != jedis) {
break;
} else {
jedis = getJedis();
}
}
String value = jedis.get(key);
returnResource(jedis);
return value;
}
/**
* 絕對設置方法(保證一定能夠使用可用的鏈接設置 數據)
* Jedis連接使用後返回連接池
* @param key
* @param time
* @param value
*/
public void safeSet(String key, int time, String value) {
Jedis jedis = getJedis();
while (true) {
if (null != jedis) {
break;
} else {
jedis = getJedis();
}
}
jedis.setex(key, time, value);
returnResource(jedis);
}
/**
* 絕對刪除方法(保證刪除絕對有效)
* Jedis連接使用後返回連接池</span>
* @param key
*/
private void safeDel(String key) {
Jedis jedis = getJedis();
while (true) {
if (null != jedis) {
break;
} else {
jedis = getJedis();
}
}
jedis.del(key);
returnResource(jedis);
}
/**
* 清除所有緩存
*/
private static void clearCache(){
CacheKit kit = new CacheKit();
Jedis jedis = getJedis();
while (true) {
if (null != jedis) {
break;
} else {
jedis = getJedis();
}
}
//PS:redis默認有一些key已經存在裏面,不能刪除,所以後面在添加key的時候用一個統一的標識符這樣將自己添加的刪除
Iterator it = jedis.keys("redis*").iterator(); //帶*號清除所有,如果寫有前綴就匹配出來sy*
while (it.hasNext()) {
String key = (String) it.next();
kit.delByCache(key); //刪除key
logger.info(new Date()+":將redis緩存"+key+"值刪除成功!");
}
returnResource(jedis);
}
/**自定義的一些 get set del 方法,方便使用 在其他地方直接調用**/
public JSONObject getByCache(String key) {
String result = safeGet(key);
if (result != null) {
return (JSONObject) JSONObject.parse(result);
}
return null;
}
public String getByCacheToString(String key) {
String result = safeGet(key);
if (result != null) {
return result;
}
return null;
}
public List<JSONObject> getArrayByCache(String key) {
String result = safeGet(key);
if (result != null) {
resultList = JSONArray.parseArray(result, JSONObject.class);
return resultList;
}
return null;
}
public JSONArray getJSONArrayByCache(String key) {
String result = safeGet(key);
if (result != null) {
return JSONArray.parseArray(result);
}
return null;
}
public void setByCache(String key, String s) {
safeSet(key, 86400, s);
}
public void setByCacheOneHour(String key, String s) {
safeSet(key, 3600, s);
}
public void setByCacheOneHour(String key, List<JSONObject> json) {
safeSet(key, 86400, JSONObject.toJSONString(json));
resultList = json;
}
public void setByCache(String key, JSONObject json) {
safeSet(key, 86400, JSONObject.toJSONString(json));
}
public void setByCache(String key, List<JSONObject> list) {
safeSet(key, 86400, JSONObject.toJSONString(list));
resultList = list;
}
public void setByCache(String key, JSONArray array) {
safeSet(key, 86400, JSONArray.toJSONString(array));
}
public void setByCacheCusTime(String key, String s, int time) {
safeSet(key, time, s);
}
public void delByCache(String key) {
//該方法刪除指定的key
if (null != safeGet(key)) {
safeDel(key);
}
}
//該方法用來清除所有相關redis的key
public void delRedisRelevantKey(){
clearCache();
}
public JSONObject toJSON(JSONObject db) {
return (JSONObject) JSONObject.toJSON(db);
}
public List<JSONObject> toJSON(List<JSONObject> list) {
List<JSONObject> json = new ArrayList<>();
for (JSONObject aList : list) {
json.add((JSONObject) JSONObject.toJSON(aList));
}
return json;
}
public boolean notNull() {
return resultList != null && resultList.size() > 0;
}
public List<JSONObject> getResult() {
return resultList;
}
public static void main(String[] args) {
//clearCache(); 到這裏自己去測試一下是否可以
}
}
之前看過其它大神的文章,都是將緩存地址放到application.properties、還有什麼application.yml裏面,但是我試過到我這裏取不到地址,試過很多方式取不到所以才決定地址放到外面,我個人覺得影響應該不會很大。
裏面也寫了很多公共方法方便調用管理。如果這裏測試沒問題那就運用到業務流程存儲數據。
RedisUtil.java
這個類用來寫redis公共方法
package com.zcwl.redis;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zcwl.goods.dto.GoodsBrand;
import net.sf.json.JSONObject;
/**
* redis緩存公共方法
* @author Liangth
*/
public class RedisUtil {
private static Logger log = LoggerFactory.getLogger(RedisUtil.class);
//redisSyIndexBrand 命名分解 redis(用來清除緩存時候,查找) SY(代表首頁比如商城:SC) 後面隨機變化
private static final String index_Brand = "redisSyIndexBrand"; //首頁推薦品牌
private static CacheKit kit = new CacheKit();
/**
* 首頁推薦品牌
* start
*/
//緩存數據
public void saveIndexBrand(List<GoodsBrand> goodsBrand){
try {
List<JSONObject> array = new ArrayList<JSONObject>();
for (int i = 0; i < goodsBrand.size(); i++) {
JSONObject object = new JSONObject();
object.put("id", goodsBrand.get(i).getId());
object.put("brandName", goodsBrand.get(i).getBrandName());
object.put("brandImg", goodsBrand.get(i).getBrandImg());
if(goodsBrand.get(i).getCountryImgUrl()==null){
object.put("countryImgUrl", "");
}else{
object.put("countryImgUrl", goodsBrand.get(i).getCountryImgUrl());
}
object.put("specialType", goodsBrand.get(i).getSpecialType());
array.add(object);
}
kit.setByCache(index_Brand, array.toString());
log.info(new Date()+":緩存數據首頁推薦品牌成功。key:"+index_Brand);
} catch (Exception e) {
log.error("數據緩存首頁推薦品牌異常,請檢查RedisUtil方法!。key:"+index_Brand);
}
}
//讀取緩存
public List<GoodsBrand> readIndexBrand(){
List<GoodsBrand> goodsBrand = new ArrayList<GoodsBrand>();
try {
List<com.alibaba.fastjson.JSONObject> list = kit.getArrayByCache(index_Brand);
for (int i = 0; i < list.size(); i++) {
GoodsBrand brand = new GoodsBrand();
brand.setId(Integer.parseInt(list.get(i).get("id").toString()));
brand.setBrandName(list.get(i).get("brandName").toString());
brand.setBrandImg(list.get(i).get("brandImg").toString());
if(list.get(i).get("countryImgUrl").toString() != null){
brand.setCountryImgUrl(list.get(i).get("countryImgUrl").toString());
}else{
brand.setCountryImgUrl("");
}
brand.setSpecialType(list.get(i).get("specialType").toString());
goodsBrand.add(brand);
}
log.info(new Date()+":讀取緩存數據首頁推薦品牌成功。key:"+index_Brand);
} catch (Exception e) {
// TODO: handle exception
log.error("讀取緩存首頁推薦品牌異常,請檢查RedisUtil方法!。key:"+index_Brand);
}
return goodsBrand;
}
/**
* end
*/
}
注意:redis數據結構以key-value存儲,所以將自己的數據結構轉換成這種方式去存儲,
3):在控制器裏面去調用上面接口
這裏應該都看得懂,我就不解釋啦。裏面有打印那些提示,在控制檯查看緩存功能是不是成功了!
4)清除緩存
我這裏暫時沒有做到數據庫和redis數據的實時同步。
現在有兩個方案可以更新:
(1)如果後臺改動數據需要馬上更新,那我們就可以在前臺觸發事件來調用後臺清理緩存接口
(2)還有設置一個定時器調用接口,到某個時間段來同步數據
阿里雲服務器安裝Redis及基本配置
請關注下一篇文章