六、spring 与redis整合的两种方式,及管道使用_事务监视执行_lua脚本实现事务保证原子性等代码示例
redis与spring的整合一般分为spring-data-redis整合和jedis整合,想了解两者的区别请移步。本片重点介绍整合的步骤,及相关的操作案例
1、通过spring-data-redis,实现jedis与Spring的整合,进而管理jedis实例、操作redis服务
1.1 如何配置
1)引入相关依赖:
<!--redis连接总结 配置--> <!--使用jedis 需要引入 commons-pool 的依赖,否则Jedis会实例化失败--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.5.6</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <!-- redis中 如果存储的是Map<String,Object>需要导入jackson相关的包,存储的时候使用json序列化器存储。如果不导入jackson的包会报错。 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.1</version> </dependency>
2)连接工厂配置文件:spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd "> <!-- 连接池基本参数配置,类似数据库连接池 --> <context:property-placeholder location="classpath:conf/redis.properties" ignore-unresolvable="true" /> <!-- redis连接池 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxActive}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <!-- 连接池配置,类似数据库连接池 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}"></property> <property name="port" value="${redis.port}"></property> <!-- <property name="password" value="${redis连接总结.pass}"></property> --> <property name="poolConfig" ref="poolConfig"></property> </bean> <!--redis操作模版,使用该对象可以操作redis --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" > <property name="connectionFactory" ref="jedisConnectionFactory" /> <!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! --> <property name="keySerializer" > <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer" > <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> </property> <!--开启事务 --> <property name="enableTransactionSupport" value="true"></property> </bean > <!-- 下面这个是整合Mybatis的二级缓存使用的:暂未验证过,先注释掉--> <!-- <bean id="redisCacheTransfer" class="cn.qlq.jedis.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory" /> </bean> --> </beans>
3)redis.properties
#访问地址 redis.host=127.0.0.1 #访问端口 redis.port=6379 #注意,如果没有password,此处不设置值,但这一项要保留 redis.password=@redisLearn #最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。 redis.maxIdle=300 #连接池的最大数据库连接数。设为0表示无限制 redis.maxActive=600 #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。 redis.maxWait=1000 #在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的; redis.testOnBorrow=true #客户端连接超时时间 redis.timeout=30000 #可用数据库数 redis.database = 0
4)在spring/spring-context.xml文件中引入:spring-redis.xml
<import resource="spring-redis.xml" />
1.2 其整合原理:
1)通过org.springframework.data.redis.connection.jedis.JedisConnectionFactory来管理,即通过工厂类管理,然后通过配置的模版bean,操作redis服务,代码段中充斥大量与业务无关的模版片段代码,代码冗余,不易维护,比如像下面的代码:
2)spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api。在RedisTemplate中提供了几个常用的接口方法的使用,并明确定义了对5种数据结构操作,具体如下:
redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
问题:StringRedisTemplate与 RedisTemplate关系
StringRedisTemplate继承RedisTemplate,两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
1.3 代码测试:
@Controller @RequestMapping("/redis") public class RedisController { //由于本地同时配置了redis 和jedis ,因此当配置jedis 时,需要注释该属性,使用redis时候再放开 @Resource(name="redisTemplate") private RedisTemplate redisTemplate; @RequestMapping("/operate.do") @ResponseBody public Map springRedisDo() { Map result=new HashMap(); // stringRedisTemplate的操作 // String读写 redisTemplate.delete("myStrKey"); redisTemplate.opsForValue().set("myStrKey", "strValue"); String strValue= (String) redisTemplate.opsForValue().get("myStrKey"); result.put("strValue",strValue); // List读写 redisTemplate.delete("myListKey"); redisTemplate.opsForList().rightPush("myListKey", "listValue1"); redisTemplate.opsForList().rightPush("myListKey", "listValue2"); redisTemplate.opsForList().leftPush("myListKey", "listValue3"); List<String> myListKeyValues = redisTemplate.opsForList().range("myListKey", 0, -1); for (String s : myListKeyValues) { System.out.println("myListKey数据元素>>>"+s); } result.put("myListKeyValues",myListKeyValues); // Set读写 redisTemplate.delete("mySet"); redisTemplate.opsForSet().add("mySetKey", "setValue1"); redisTemplate.opsForSet().add("mySetKey", "setValue2"); redisTemplate.opsForSet().add("mySetKey", "setValue3"); redisTemplate.opsForSet().add("mySetKey", "setValue3"); redisTemplate.opsForSet().add("mySetKey", "setValue3"); Set<String> setValues = redisTemplate.opsForSet().members("mySetKey"); for (String s : setValues) { System.out.println("mySetKey数据元素>>>"+s); } result.put("setValues",setValues); // Hash读写 redisTemplate.delete("myHashKey"); redisTemplate.opsForHash().put("myHashKey", "BJ", "北京"); redisTemplate.opsForHash().put("myHashKey", "SH", "上海"); redisTemplate.opsForHash().put("myHashKey", "TJ", "天津"); Map<String, String> hashValues = redisTemplate.opsForHash().entries("myHashKey"); List myHashList= redisTemplate.opsForHash().values("myHashKey"); System.out.println("myHashList数据信息>>>"+myHashList); for (Map.Entry entry : hashValues.entrySet()) { System.out.println("myHashValues>>>"+entry.getKey() + " - " + entry.getValue()); } result.put("hashValues",hashValues); return result; } }
2、通过jedis,实现redis与Spring的整合,进而管理jedis实例、操作redis服务
2.1 如何配置
1)引入相关依赖:使用jedis 需要引入 commons-pool 的依赖,否则Jedis会实例化失败
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.5.6</version> </dependency>
2)连接池配置文件:spring-jedis.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd "> <!-- 连接池基本参数配置,类似数据库连接池 --> <context:property-placeholder location="classpath:conf/redis.properties" ignore-unresolvable="true" /> <!-- redis连接池 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxActive}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="poolConfig" /> <constructor-arg name="host" value="${redis.host}" /> <constructor-arg name="port" value="${redis.port}" type="int" /> <constructor-arg name="timeout" value="${redis.timeout}" type="int" /> <constructor-arg name="password" value="${redis.password}" /> <constructor-arg name="database" value="${redis.database}" type="int" /> </bean> <!-- 集群方式:暂未进行测试,因此先注释掉 --> <!-- <bean id="shardedJedisPool" class="jedis.clients.jedis.ShardedJedisPool" scope="singleton"> <constructor-arg index="0" ref="poolConfig" /> <constructor-arg index="1"> <list> <bean class="jedis.clients.jedis.JedisShardInfo"> <constructor-arg name="host" value="${jedis.host}" /> </bean> </list> </constructor-arg> </bean> --> <!-- 下面这个是整合Mybatis的二级缓存使用的:暂未进行测试,因此先注释掉 --> <!-- <bean id="redisCacheTransfer" class="cn.qlq.jedis.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory" /> </bean> --> </beans>
3)redis.properties同1.1中的
4)在spring/spring-context.xml文件中引入:spring-jedis.xml
<import resource="spring-jedis.xml" />
2.2)通过jedis方式的理论:
通过redis.clients.jedis.JedisPool 连接池进行连接管理,通过池对象获取jedis实例,然后通过jedis实例直接操作redis服务,剔除了与业务无关的冗余代码,从工厂类到池的方式变化,就相当于mybatis连接mysql方变化是一样的,代码变得更简洁,维护也更容易了。Jedis使用apache commons-pool2对Jedis资源池进行管理,所以在定义JedisPool时一个很重要的参数就是资源池GenericObjectPoolConfig,使用方式如下,其中有很多资源管理和使用的参数。如下面的代码片段
private JedisPool jedisPool;
public String save(String key,String val) {
Jedis jedis = jedisPool.getResource();
return jedis.set(key, val);
}
2.3)代码测试:包含管道使用、批次查询、删除、事务监视执行、lua脚本实现事务保证原子性
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)下 锁的应用,待补充 }
参看博文:
https://www.cnblogs.com/qlqwjy/p/8562703.html
https://www.cnblogs.com/wlandwl/p/redis.html redis介绍及jedis基础操作
https://blog.csdn.net/zxl646801924/article/details/82770026 redis和jedis的用法区别
https://www.cnblogs.com/liuqingzheng/p/9831331.html window redis 安装
https://blog.csdn.net/rexueqingchun/article/details/79803949 项目中引入jedis
https://www.cnblogs.com/springlight/tag/redis/ redis 相关学习
https://blog.csdn.net/li1376417539/article/details/104951358/ spring官方文档中文
https://spring.io/projects/spring-data-redis spring 整合redis
https://www.cnblogs.com/yiwangzhibujian/p/7053840.html redis相关
https://blog.csdn.net/j16421881/article/details/78764287 commons-pool
及对开发工作中用到的代码进行总结
如有疑问,欢迎留言!
细水长流,打磨濡染,渐趋极致,才是一个人最好的状态。