• 六、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>
    View Code
        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>
    View Code
        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
    View Code
        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;
            }
        }
    View Code
    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>
    View Code
        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>
    View Code
        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)下 锁的应用,待补充
    
        }
    View Code
    
    
    参看博文:
    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
    及对开发工作中用到的代码进行总结
    如有疑问,欢迎留言!

  • 相关阅读:
    静态构造函数(C# 编程指南)
    SQL SERVER2008 存储过程、表、视图、函数的权限
    EF架构~为EF DbContext生成的实体添加注释 【转】
    WebBrowser 多线程问题,寻求解答!(已经搞清楚!) 【转】
    EF架构~将数据库注释添加导入到模型实体类中 【转】
    window.name web开发iframe 跨域间的值传输问题
    javascript 验证 国际格式 电话号码
    认识HTML5的WebSocket
    Jquery 滚屏
    哎 为了自己的生活能过的去 从今天起开始写技术博客 请大家多多指教
  • 原文地址:https://www.cnblogs.com/jiarui-zjb/p/14311506.html
Copyright © 2020-2023  润新知