Redis在線管理篇
一.引入
Redis是什麼:搜索引擎上面一大推,這裏不說了。
Redis特點:性能極高 – Redis能支持超過 100K+ 每秒的讀寫頻率,同時具備豐富的數據類型 – 支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作......
因此Redis用作爲高速緩存場景非常適合,(如:集羣環境下session的存儲,新提醒等)。
然而redis大多數都是通過client進行管理的,對於系統用戶來說,不能直接圖形化管理redis數據是一個弊端,此篇文章就記錄一下開發redis在線管理的要點。
二.操作要點
先上代碼吧
1. 配置文件 redis.properties
#============ Redis Configuration Begin ==========#
redis_host=127.0.0.1
redis_port=6379
redis_pwd=123456
redis_maxTotal=200
redis_maxIdle=50
redis_minIdle=10
redis_maxWaitMillis=10000
#============= Redis Configuration End ===========#
2. 讀取配置文件:PropertiesHandler.java
import java.io.InputStream;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 讀取屬性配置文件
* @author yannguo
*/
public class PropertiesHandler {
private static Logger log = LoggerFactory.getLogger(PropertiesHandler.class);
private static Properties defaultProperties;
static {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = PropertiesHandler.class.getClassLoader();
}
try {
if (log.isDebugEnabled()) {
log.debug("開始裝載屬性資源參數文件...");
}
InputStream is = classLoader.getResourceAsStream("redis.properties");
defaultProperties = new Properties();
defaultProperties.load(is);
} catch (Exception e) {
try {
throw new Exception("裝載屬性資源參數文件出錯.", e);
} catch (Exception e1) {
}
}
}
/**
* 返回缺省屬性文件[application.properties]屬性值
*
* @param pKey
* @return String
*/
public static String getProperty(String pKey) {
String value = defaultProperties.getProperty(pKey, "");
return value;
}
}
3. Redis工具類 JedisUtil.java
package com.hfmx.utils.redis;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gson.Gson;
import com.hfmx.formmodel.redis.FRedisModel;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Redis客戶端
* @author yangnuo
*/
@SuppressWarnings("deprecation")
public class JedisUtil {
// private static Logger logger = LoggerFactory.getLogger(JedisUtil.class);
// 連接池對象
private static JedisPool jedisPool;
static {
String host = PropertiesHandler.getProperty("redis_host");
int port = Integer.valueOf(PropertiesHandler.getProperty("redis_port"));
String password = PropertiesHandler.getProperty("redis_pwd");
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.valueOf(PropertiesHandler.getProperty("redis_maxTotal")));
config.setMaxIdle(Integer.valueOf(PropertiesHandler.getProperty("redis_maxIdle")));
config.setMinIdle(Integer.valueOf(PropertiesHandler.getProperty("redis_minIdle")));
config.setMaxWaitMillis(Integer.valueOf(PropertiesHandler.getProperty("redis_maxWaitMillis")));
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
//Idle時進行連接掃描
config.setTestWhileIdle(true);
//表示idle object evitor兩次掃描之間要sleep的毫秒數
config.setTimeBetweenEvictionRunsMillis(30000);
//表示idle object evitor每次掃描的最多的對象數
config.setNumTestsPerEvictionRun(10);
//表示一個對象至少停留在idle狀態的最短時間,然後才能被idle object evitor掃描並驅逐;這一項只有在timeBetweenEvictionRunsMillis大於0時纔有意義
config.setMinEvictableIdleTimeMillis(60000);
if (JHCJUtils.isEmpty(password)) {
jedisPool = new JedisPool(config, host, port);
}else{
jedisPool = new JedisPool(config, host, port, 0, password);
}
}
/**
* 獲取Jedis連接客戶端
*
* @return
*/
public static Jedis getJedisClient() {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
} catch (Exception e) {
// logger.error("獲取Redis客戶端連接失敗。");
System.out.println("錯誤:[獲取Redis客戶端連接失敗]");
e.printStackTrace();
}
if (jedis == null) {
// logger.warn("沒有獲取到Redis客戶端連接。");
System.out.println("警告:[沒有獲取到Redis客戶端連接]");
}
return jedis;
}
/**
* 安全回收資源
*
* @param jedis
*/
public static void close(Jedis jedis) {
try {
jedisPool.returnResource(jedis);
} catch (Exception e) {
if (jedis.isConnected()) {
jedis.quit();
jedis.disconnect();
}
}
}
/**
* 設置字符串型數據
*
* @param key
* 存儲鍵
* @param value
* 存儲值
* @param timeout
* 超時時間(單位:秒) 設置爲0,則無時效性。
* @return
*/
public static void setString(String key, String value, int timeout) {
if (JHCJUtils.isEmpty(key)) {
throw new NullPointerException("Key不能爲空!");
}
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.set(key, value);
if (timeout > 0) {
jedis.expire(key, timeout);
}
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* 設置字符串型數據過期時間
*
* @param key
* 存儲鍵
* @param timeout
* 超時時間(單位:秒)
* @param key
*/
public static void exprString(String key, int timeout) {
if (JHCJUtils.isEmpty(key)) {
return;
}
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.expire(key, timeout);
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* 設置序列化對象數據
*
* @param key
* 存儲鍵
* @param value
* 存儲值
* @param timeout
* 超時時間(單位:秒) 設置爲0,則無時效性。
* @return
*/
public static void setObj(String key, byte[] value, int timeout) {
if (JHCJUtils.isEmpty(key)) {
throw new NullPointerException("Key不能爲空!");
}
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.set(key.getBytes(), value);
if (timeout > 0) {
jedis.expire(key, timeout);
}
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* 添加集合數據
* @param type
* @param obj
* @param existtime
*/
public static void addAggregate(FRedisModel redisModel){
Jedis jedis = JedisUtil.getJedisClient();
if(redisModel.getType().equals("list")){
List list = (List) redisModel.getVal();
for (int i=0;i<list.size();i++) {
jedis.lpush(redisModel.getKey(), new Gson().toJson(list.get(i)));
}
}else if(redisModel.getType().equals("set")){
Set set = (Set) redisModel.getVal();
for (Object object : set) {
jedis.sadd(redisModel.getKey(), new Gson().toJson(object));
}
}else if(redisModel.getType().equals("hashObj")){
jedis.hmset(redisModel.getKey().getBytes(),(Map<byte[], byte[]>) redisModel.getVal());
}else if(redisModel.getType().equals("hashStr")){
jedis.hmset(redisModel.getKey(), (Map<String, String>) redisModel.getVal());
}
if (redisModel.getExisttime() > 0) {
jedis.expire(redisModel.getKey(), (int)redisModel.getExisttime());
}
JedisUtil.close(jedis);
System.out.println("完成添加 ["+redisModel.getType()+"] 集合");
}
/**
* 獲取字符串型數據
*
* @param key
* @return
*/
public static String getString(String key) {
if (JHCJUtils.isEmpty(key)) {
throw new NullPointerException("Key不能爲空!");
}
String value = null;
Jedis jedis = null;
try {
jedis = getJedisClient();
value = jedis.get(key);
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
return value;
}
/**
* 獲取序列化對象數據
*
* @param key
* @return
*/
public static byte[] getObj(String key) {
if (JHCJUtils.isEmpty(key)) {
throw new NullPointerException("Key不能爲空!");
}
byte[] value = null;
Jedis jedis = null;
try {
jedis = getJedisClient();
value = jedis.get(key.getBytes());
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
return value;
}
/**
* 刪除對象數據
*
* @param key
*/
public static void delObj(String key) {
if (JHCJUtils.isEmpty(key)) {
return;
}
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.del(key.getBytes());
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* 刪除字符串數據
*
* @param key
*/
public static void delString(String key) {
if (JHCJUtils.isEmpty(key)) {
return;
}
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.del(key);
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* 清除DB
*
* @param key
*/
public static void flushDB() {
Jedis jedis = null;
try {
jedis = getJedisClient();
jedis.flushDB();
// logger.info("Redsi緩存DB重置成功。");
System.out.println("輸出:[Redsi緩存DB重置成功]");
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
// logger.error("操作Redis失敗", e);
System.out.println("錯誤:[操作Redis失敗]");
} finally {
close(jedis);
}
}
/**
* Object轉換byte[]類型
* @param object
* @return
*/
public static byte[] toBytes(Object object){
return serialize(object);
}
/**
* 對象轉 byte[]
* @param obj
* @return
*/
public static byte[] serialize (Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray ();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
}
/**
* 測試
*/
public static void main(String[] args) {
Jedis jedis = JedisUtil.getJedisClient();
jedis.set("XC", "1");
System.out.println(jedis.get("XC"));
System.out.println(jedis.info());
JedisUtil.close(jedis);
}
}
4. Redis實體類 FRedisModel.java
public class FRedisModel implements Serializable{
private String key;
private String type;
private Object val;
private long existtime;
public FRedisModel(String key, String type, Object val, long existtime) {
this.key = key;
this.type = type;
this.val = val;
this.existtime = existtime;
}
public FRedisModel() {
}
get方法
set方法
}
說明: JedisUtil.addAggregate(FRedisModel) 用來存儲集合數據的
list : FRedisModel(String key, "list", Object val, long existtime)
set: FRedisModel(String key, "set", Object val, long existtime)
map<String,String>: FRedisModel(String key, "hashStr", Object val, long existtime)
map<String,Object>: FRedisModel(String key, "hashObj", Object val, long existtime)
注意:存儲Map集合,優點特殊,需要區分是對象還是字符串,存儲的對象必須是序列化的
使用方法 JedisUtil.serialize(Obj) 進行序列化
JedisUtil.setString(String key, String value, int timeout) 用來存儲普通字符串
JedisUtil.flushDB() 清空Redis所有數據信息
其他方法自己看吧,都有註釋的
這裏寫一些 添加集合數據的示例:
//添加list
List<TestUser> list = new ArrayList<TestUser>();
for(int i=0;i<100;i++){
list.add(new TestUser("哈哈"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date())));
}
FRedisModel redisModel_list = new FRedisModel("list_"+UUID.randomUUID().toString(), "list", list, 3600);
JedisUtil.addAggregate(redisModel_list);
//添加對象 Hashmap
Map<byte[], byte[]> hashObj = new HashMap<byte[], byte[]>();
TestUser t1 = new TestUser("落花雨1111"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
TestUser t2 = new TestUser("落花雨2222"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
TestUser t3 = new TestUser("落花雨3333"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
hashObj.put("1111".getBytes(), JedisUtil.serialize(t1));
hashObj.put("2222".getBytes(), JedisUtil.serialize(t2));
hashObj.put("3333".getBytes(), JedisUtil.serialize(t3));
FRedisModel redisModel_mapObj = new FRedisModel("hash_"+UUID.randomUUID().toString(), "hashObj", hashObj, 3600);
JedisUtil.addAggregate(redisModel_mapObj);
//添加字符串 HashMap
Map<String,String> hashStr = new HashMap<String, String>();
hashStr.put("1111", "第一號");
hashStr.put("2222", "第二號");
hashStr.put("3333", "第三號");
FRedisModel redisModel_mapStr = new FRedisModel("hash_"+UUID.randomUUID().toString(), "hashStr", hashStr, 3600);
JedisUtil.addAggregate(redisModel_mapStr);
//添加set
Set<TestUser> set = new HashSet<TestUser>();
TestUser t4 = new TestUser("4444"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
TestUser t5 = new TestUser("5555"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
TestUser t6 = new TestUser("6666"+new SimpleDateFormat("HHmmssSS").format(new Date()), new SimpleDateFormat("SS").format(new Date()), new SimpleDateFormat("HHmmssSS").format(new Date()));
set.add(t4);
set.add(t5);
set.add(t6);
FRedisModel redisModelset = new FRedisModel("set_"+UUID.randomUUID().toString(), "set", set, 3600);
JedisUtil.addAggregate(redisModelset);
5. CatchManage.java 用來處理前臺的分頁查詢所有key的請求,以及通過key來查詢詳細的數據信息,並返回,相當於service功能
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import com.google.gson.Gson;
import redis.clients.jedis.Jedis;
public class CatchManage {
/**
* 查詢緩存DB中的Key
*
* @return
*/
public List<FRedisModel> listKeys(int start,int end) {
Jedis jedis = JedisUtil.getJedisClient();
Set<String> keySet = jedis.keys("*");
List<String> keyList = new ArrayList<String>(keySet);
List<FRedisModel> list = new ArrayList<FRedisModel>();
for (String key_ : keyList) {
FRedisModel fredi = new FRedisModel();
fredi.setKey(key_);
fredi.setType(jedis.type(key_));
long ttl_ = jedis.ttl(key_);
fredi.setExisttime(ttl_);
list.add(fredi);
}
JedisUtil.close(jedis);
int allnum = keyList.size();
start = Integer.valueOf(start);
// end = start + Integer.valueOf(end);
end = end > list.size() ? list.size() : end;
List<FRedisModel> outList = list.subList(start, end);
return outList;
}
/**
* 查詢緩存DB中的Key 支持分頁
* @param start
* @param end
* @return
*/
public DataGrid<Map<String, Object>> listKeysPageNation(int start,int end) {
Jedis jedis = JedisUtil.getJedisClient();
Set<String> keySet = jedis.keys("*");
List<String> keyList = new ArrayList<String>(keySet);
List<FRedisModel> list = new ArrayList<FRedisModel>();
for (String key_ : keyList) {
FRedisModel fredi = new FRedisModel();
fredi.setKey(key_);
fredi.setType(jedis.type(key_));
long ttl_ = jedis.ttl(key_);
fredi.setExisttime(ttl_);
list.add(fredi);
}
JedisUtil.close(jedis);
int allnum = keyList.size();
start = Integer.valueOf(start);
end = end > list.size() ? list.size() : end;
//分頁顯示
List<FRedisModel> outList = list.subList(start, end);
//包裝成DataGrid
DataGrid<Map<String, Object>> grid = new DataGrid<Map<String, Object>>();
List<Map<String, Object>> listmap = new ArrayList<Map<String, Object>>();
for (FRedisModel fRedisModel : outList) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("key", fRedisModel.getKey());
map.put("type", fRedisModel.getType());
map.put("existtime", fRedisModel.getExisttime());
listmap.add(map);
}
grid.setTotal(allnum);
grid.setRows(listmap);
return grid;
}
/**
* 通過 key 來查找對應的 值
*
* 數據類型 list hashmap set String
* @param key_
* @return
*/
public List<FRedisModel> getValByKey(FRedisModel redisModel) {
System.out.println("redis將要查找的數據類型:"+redisModel.getType()+" key:"+redisModel.getKey()+" 存在時間"+redisModel.getExisttime());
List<FRedisModel> outList = new ArrayList<FRedisModel>();
Jedis jedis = JedisUtil.getJedisClient();
if (StringUtils.equalsIgnoreCase(redisModel.getType(), "string")) {
redisModel.setVal(jedis.get(redisModel.getKey()));
outList.add(redisModel);
} else if (StringUtils.equalsIgnoreCase(redisModel.getType(), "hash")) {
Set<String> fieldSet = jedis.hkeys(redisModel.getKey());
List<String> fiedList = new ArrayList<String>(fieldSet);
System.out.println("fieldSet size:"+fieldSet.size());
for (String value : fiedList){
System.out.println("value->"+value);
outList.add(new FRedisModel(redisModel.getKey(), redisModel.getType(), jedis.hget(redisModel.getKey(), value), redisModel.getExisttime()));
}
} else if (StringUtils.equalsIgnoreCase(redisModel.getType(), "list")) {
List valueList = jedis.lrange(redisModel.getKey(), 0, -1);
for (Object value : valueList) {
outList.add(new FRedisModel(redisModel.getKey(), redisModel.getType(), value, redisModel.getExisttime()));
}
} else if (StringUtils.equalsIgnoreCase(redisModel.getType(), "set")) {
// 由於API的限制,不能對SET類型進行有效的分頁操作。所以隨機取出10000條記錄返回。
List valueList = jedis.srandmember(redisModel.getKey(), 10000);
for (Object value : valueList) {
outList.add(new FRedisModel(redisModel.getKey(), redisModel.getType(), value, redisModel.getExisttime()));
}
}
JedisUtil.close(jedis);
return outList;
}
}
由於不能泄露代碼,所以只寫了主要的部分,看懂了這些,其他的controller層應該很好寫的。時間緊,寫的比較粗糙,望見諒!