import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* @Copyright (C), 2002-2020,
* @ClassName: JedisController
* @Author:
* @Date: 2020/9/8 11:04
* @Description:
* @History:
* @Version:1.0
*/
@Controller
@RequestMapping("/jedis/")
public class JedisController {
@Autowired
private JedisPool jedisPool;
@Autowired
private com.zj.weblearn.jedis.JedisClient jedisClient;
/**
* @Method:
* @Author:
* @Description: param: 通过jedis客户端,往Redis中 存入数据
* @Return:
* @Exception:
* @Date: 2020/9/10 10:38
*/
@RequestMapping("save")
@ResponseBody
public Map getSave(String key, String val) {
Map result = new HashMap();
boolean executeResult = false;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, val);
executeResult = true;
} catch (Exception e) {
System.out.println("获取jedis链接异常" + e);
}
result.put("executeResult", executeResult);
return result;
}
/**
* @Method:
* @Author:
* @Description: param: 查询Redis中存储的信息
* @Return:
* @Exception:
* @Date: 2020/9/10 10:40
*/
@RequestMapping("queryKeyInfo.do")
@ResponseBody
public Map getKey(String key) {
Map result = new HashMap();
Jedis jedis = jedisPool.getResource();
String redisValue = jedis.get(key);
result.put("key", redisValue);
return result;
}
//http://localhost:8080/jedis/hmset.do?userCode=122222
@RequestMapping("saveHashSet.do")
@ResponseBody
public Map saveHmset(String userCode) {
Map result = new HashMap();
Map hash = new HashMap();
hash.put("userName", "ceshi");
hash.put("userRole", "shenHe");
jedisClient.hmset(userCode, hash);
result.put("userCode", jedisClient.hgetAll(userCode));
return result;
}
//http://localhost:8080/jedis/toHincrBy.do?key=122222&field=level&value=2
@RequestMapping("toHincrBy.do")
@ResponseBody
public Map toHincrBy(String key, String field, long value) {
Map result = new HashMap();
result.put("increaseAfterVal", jedisClient.hincrBy(key, field, value));
return result;
}
@RequestMapping("pipeline.do")
@ResponseBody
public Map testPipeline() {
Map<String, String> resultMap = new HashMap<>();
try {
//1.操作数据准备
Map<String, String> notPipeLineparamMap = new HashMap<>();
List<String> keyList=new ArrayList<>();
Map<String, String> pipeLineparamMap = new HashMap<>();
for (int i = 0; i < 10000; i++) {
notPipeLineparamMap.put("key_" + i, String.valueOf(i));
pipeLineparamMap.put("pkey_" + i, String.valueOf(i));
keyList.add("pkey_" + i);
}
//2.通过非pipeline操作数据写入记时
long setStart = System.currentTimeMillis();
for (Map.Entry<String, String> entry : notPipeLineparamMap.entrySet()) {
jedisClient.set(entry.getKey(), entry.getValue());
}
long setEnd = System.currentTimeMillis();
resultMap.put("非pipeline操作10000次字符串数据类型set写入,耗时:", (setEnd - setStart) + "毫秒");
//3.pipeline操作数据写入记时
long pipelineStart = System.currentTimeMillis();
jedisClient.setPassPipeline(pipeLineparamMap);
long pipelineEnd = System.currentTimeMillis();
resultMap.put("pipeline操作10000次字符串数据类型set写入,耗时:", (pipelineEnd - pipelineStart) + "毫秒");
//4.通过非pipeline操作删除数据
long delStart = System.currentTimeMillis();
for (Map.Entry<String, String> entry : notPipeLineparamMap.entrySet()) {
//jedisClient.del(entry.getKey());
}
long delEnd = System.currentTimeMillis();
resultMap.put("非pipeline操作10000次字符串数据类型del删除,耗时:", (delEnd - delStart) + "毫秒");
//5.通过pipeline操作删除数据局
long pipelineDelStart = System.currentTimeMillis();
jedisClient.delPassPipeline(pipeLineparamMap);
long pipelineDelEnd = System.currentTimeMillis();
resultMap.put("pipeline操作10000次字符串数据类型del删除,耗时:", (pipelineDelEnd - pipelineDelStart) + "毫秒");
//6.通过管道批次读取数据
jedisClient.readPassPipeline(keyList);
} catch (Exception e) {
System.out.println("e>>>>>"+e);
e.printStackTrace();
}
return resultMap;
}
/**
* @Method:
* @Author:
* @Description: redis 自身提供Transaction 是一个假的事务,其是无法保证事务的原子性的
* param:
* @Return:
* @Exception:
* @Date: 2020/9/17 17:47
*/
@RequestMapping("transaction.do")
@ResponseBody
public Map testTransaction() {
Map<String, Object> resultMap = new HashMap<>();
List<Object> execObjectList = null;
try {
Jedis jedis = jedisClient.getJedis();
jedis.watch("userLevel", "root");
//使用watch监视key,此时在事务执行前key被改动,事务将取消不会执行所有命令;
Transaction transaction = jedis.multi();
transaction.set("userLevel", "normal");
transaction.set("userAddress", "beijing");
execObjectList = transaction.exec();
jedis.close();
resultMap.put("isSuccess", true);
} catch (Exception e) {
resultMap.put("isSuccess", false);
}
return resultMap;
}
/**
* @Method:
* @Author:
* @Description: 在redis中可通过Lua 脚本实现事务,保证原子性
* param:
* @Return:
* @Exception:
* @Date: 2020/9/17 17:47
*/
@RequestMapping("transactionOperateByLua.do")
@ResponseBody
public Map transactionOperateByLua() {
Map<String, Object> resultMap = new HashMap<>();
List<Object> execObjectList = null;
List<String> keys = new ArrayList<>();
keys.add("name");
keys.add("age");
List<String> values = new ArrayList<>();
values.add("kevin");
values.add("25");
try {
Jedis jedis = jedisClient.getJedis();
jedis.eval("redis.call('set', KEYS[1], ARGV[1]) redis.call('set', KEYS[2], ARGV[2])", keys, values);
jedis.close();
resultMap.put("isSuccess", true);
} catch (Exception e) {
resultMap.put("isSuccess", false);
}
return resultMap;
}
/**
* @Method:
* @Author:
* @Description: 在redis中可通过Lua 脚本实现事务,保证原子性
* param:
* @Return:
* @Exception:
* @Date: 2020/9/17 17:47
*/
@RequestMapping("distributedLock.do")
@ResponseBody
public Map distributedLock(String testKey) {
Map<String, Object> resultMap = new HashMap<>();
try {
Assert.isTrue(StringUtils.isNotBlank(testKey), "key不能为空");
String key="distributeKey";
String value="distributeVal";
long expireTime=60L;
String replyCode=jedisClient.nxPxSet(key,value,expireTime);
resultMap.put("isSuccess", true);
resultMap.put("replyCode", replyCode);
} catch (Exception e) {
resultMap.put("isSuccess", false);
}
return resultMap;
}
}
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/*
* @Copyright (C), 2002-2020,
* @ClassName: JedisClient
* @Author:
* @Date: 2020/9/16 9:35
* @Description:
* @History:
* @Version:1.0
*/
@Service("jedisClient")
public class JedisClient {
private static final Logger LOGGER = LoggerFactory.getLogger(JedisClient.class);
@Autowired
private JedisPool jedisPool;
/**
* 将key 的值设为value ,当且仅当key 不存在,等效于 SETNX
*/
public static final String NX = "NX";
/**
* seconds — 以秒为单位设置 key 的过期时间,等效于EXPIRE key seconds
*/
public static final String EX = "EX";
public static final int FIVE_MIN = 300; // 5分钟
/**
* 功能描述: <br>
* [功能描述]:保存key,value格式的数据
* [应用场景]:
*/
public void set(final String key, String val) {
Jedis jedis = jedisPool.getResource();
jedis.set(key, val);
jedis.close();
}
/*
* 设置redis的值 常用方法 SETNX works exactly like SET with the only difference that
* if the key already exists no operation is performed. SETNX actually means
* "SET if Not eXists".
*/
public Long setnx(final String key, String val) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.setnx(key, val);
final int seconds = getExpire(key);
if (result == 1 && seconds > 0) {
jedis.expire(key, seconds);
}
jedis.close();
return result;
}
/**
* 得到过期时间,如果出现异常,默认五分钟过期
* @param key
* @throws ParseException
*/
public static int getExpire(String key) {
if (key == null)
return FIVE_MIN; // key不存在,那么5秒钟过期。
try {
String vkey = getExpireRule(key);
String tag1 = "{exp=";
String tag2 = "{exp:";
if (vkey.indexOf(tag1) > -1 || vkey.indexOf(tag2) > -1) {
if (vkey.indexOf(tag1) > -1) {
vkey = vkey.substring(vkey.indexOf(tag1) + tag1.length());
}
if (vkey.indexOf(tag2) > -1) {
vkey = vkey.substring(vkey.indexOf(tag2) + tag2.length());
}
vkey = vkey.substring(0, vkey.indexOf("}"));
if (vkey.startsWith("to:")) {
int time_sec = getExpireToConstructs(vkey);
return time_sec;
// 到整点小时过期,加上随机数防止并发压力,时间紧简单写,以后整理
} else if (vkey.startsWith("every:1h")) {
int time_sec = getExpireEveryOneConstructs();
return time_sec;
} else if (vkey.startsWith("every:2h")) {
int time_sec = getExpireEveryTwoConstructs();
return time_sec;
} else {
return Integer.parseInt(vkey);
}
} else {
return FIVE_MIN;
}
} catch (Exception e) {
// 出异常默认为5分钟过期
LOGGER.error(e.getMessage(), e);
return FIVE_MIN;
}
}
public static int getExpireEveryTwoConstructs() {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 2);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
int time_sec = Math.round((float) (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000);
if (time_sec <= 0) {
time_sec = FIVE_MIN;
}
return time_sec;
}
public static int getExpireToConstructs(String vkey) {
int toDay = Integer.parseInt(vkey.substring(3, vkey.indexOf("/")));
String time = vkey.substring(vkey.indexOf("/") + 1);
if (time.indexOf(":") == time.lastIndexOf(":")) {
time += ":00";
}
SimpleDateFormat onlyDate = new SimpleDateFormat("yyyy-MM-dd");
String strToDate = onlyDate.format(DateUtils.addDays(new Date(), toDay)) + " " + time;
Timestamp toDate = Timestamp.valueOf(strToDate);
long toTime = toDate.getTime();
int time_sec = Math.round((float) (toTime - System.currentTimeMillis()) / 1000);
if (time_sec <= 0) {
time_sec = FIVE_MIN;
}
return time_sec;
}
public static int getExpireEveryOneConstructs() {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, new Random().nextInt(30));
int time_sec = Math.round((float) (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000);
if (time_sec <= 0) {
time_sec = FIVE_MIN;
}
return time_sec;
}
/**
* 默认的过期时间是5分钟
*/
public static String getExpireRule(String key) {
if (key == null)
return "{exp=" + FIVE_MIN + "}";
String vkey = key.toLowerCase().replaceAll(" ", "");
String tag1 = "{exp=";
String tag2 = "{exp:";
try {
String expireRule = "";
if (vkey.indexOf(tag1) > -1 || vkey.indexOf(tag2) > -1) {
if (vkey.indexOf(tag1) > -1) {
expireRule = vkey.substring(vkey.indexOf(tag1));
} else if (vkey.indexOf(tag2) > -1) {
expireRule = vkey.substring(vkey.indexOf(tag2));
}
expireRule = expireRule.substring(0, expireRule.indexOf("}") + 1);
return expireRule.toLowerCase();
} else {
return "{exp=" + FIVE_MIN + "}";// 默认都5分钟过期
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return "{exp=" + FIVE_MIN + "}";
}
}
/**
* 功能描述: <br>
* [功能描述]:通过管道进行批次 保存key,value格式的数据
* [应用场景]:pipeline提供了命令的批量提交,当我们有批量查询或者写入操作时,通过pipeline可以很大程度上控制网络开销
*/
public void setPassPipeline(Map<String, String> valMap) {
Jedis jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
for (Map.Entry<String, String> entry : valMap.entrySet()) {
pipeline.set(entry.getKey(), entry.getValue());
}
pipeline.sync();
jedis.close();
}
/**
* 功能描述: <br>
* [功能描述]:删除redis 中指定的key的存储信息
* [应用场景]:
*/
public void del(final String key) {
Jedis jedis = jedisPool.getResource();
jedis.del(key);
jedis.close();
}
/**
* 功能描述: <br>
* [功能描述]:通过管道进行批次删除key的数据
* [应用场景]:pipeline提供了命令的批量提交,当我们有批量查询或者写入操作时,通过pipeline可以很大程度上控制网络开销
*/
public void delPassPipeline(Map<String, String> valMap) {
Jedis jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
for (Map.Entry<String, String> entry : valMap.entrySet()) {
pipeline.del(entry.getKey());
}
pipeline.sync();
jedis.close();
}
/**
* @Method:
* @Author:
* @Description: 通过管道批次读取
* param:
* @Return:
* @Exception:
* @Date: 2020/11/12 15:42
*/
public void readPassPipeline(List<String> keys) {
Jedis jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
Map<String,Map<String,String>> result = new HashMap<String,Map<String,String>>();
//使用pipeline hgetall
Map<String, Response<Map<String,String>>> responses = new HashMap<String,Response<Map<String,String>>>(keys.size());
long start = System.currentTimeMillis();
for(String key : keys) {
responses.put(key, pipeline.hgetAll(key));
}
pipeline.sync();
for(String k : responses.keySet()) {
result.put(k, responses.get(k).get());
}
System.out.println("result>>>>"+result);
long end = System.currentTimeMillis();
System.out.println("result size:[" + result.size() + "] ..");
System.out.println("hgetAll with pipeline used [" + (end - start) / 1000 + "] seconds ..");
jedis.disconnect();
}
/**
* 功能描述: <br>
* [功能描述]:同时将多个 field-value (域-值)对设置到哈希表 key 中。
* [应用场景]:
*/
public void hmset(final String key, final Map<String, String> hash) {
Jedis jedis = jedisPool.getResource();
jedis.hmset(key, hash);
jedis.close();
}
/**
* 功能描述: <br>
* [功能描述]:一次获取哈希表 key 的值(多个 field-value (域-值))
* [应用场景]:
*/
public Map hgetAll(final String key) {
Jedis jedis = jedisPool.getResource();
Map result = jedis.hgetAll(key);
jedis.close();
return result;
}
/**
* 功能描述: <br>
* [功能描述]:为哈希表 key 中的域 field 的值加上增量 increment 。
* [应用场景]:
*/
public Long hincrBy(final String key, final String field, final long value) {
Jedis jedis = jedisPool.getResource();
long result = jedis.hincrBy(key, field, value);
jedis.close();
return result;
}
/**
* 功能描述: <br>
* [功能描述]:<br>
* 将字符串值 value 关联到 key 。<br>
* 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。<br>
* 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。<br>
* seconds 过去时间(秒)
* 如果服务器返回 OK ,那么这个客户端获得锁。
* 如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。
* [应用场景]:
*/
public String nxPxSet(final String key, final String value, final long time) {
Jedis jedis = jedisPool.getResource();
String replyCode = jedis.set(key, value, NX, EX, time);
jedis.close();
return replyCode;
}
/**
* 功能描述: <br>
* [功能描述]:获取jedis对象
* [应用场景]:
*/
public Jedis getJedis() {
Jedis jedis = jedisPool.getResource();
return jedis;
}
/**
* 功能描述: <br>
* [功能描述]:关闭jedis对象
* [应用场景]:
*/
public void closeJedis(Jedis jedis) {
jedis.close();
}
/**
* 返回名称为key的set的所有元素 Return all the members (elements) of the set value
* stored at key. This is just syntax glue for SINTER.
*/
public Set<String> smembers(final String key) {
Jedis jedis = jedisPool.getResource();
Set<String> setResult = jedis.smembers(key);
jedis.close();
return setResult;
}
//redis 在分布式(Distributed)下 锁的应用,待补充
}