redis

一、什么是redis

  redis是nosql数据库的一种,其基于可基于内存亦可持久化的日志型、Key-Value数据库。redis相比于memcached有更丰富的数据类型,并且能够持久化。由于redis是基于内存的数据库,所以其读写性能非常强大。

由于redis是单线程的,所以redis的操作都是原子操作,是线程安全的。

二、redis有哪些用途

  1、配合关系型数据库做高速缓存,缓存热点数据减少数据库io操作。

  2、服务器集群中做session共享,如单点登录等。

  3、当作计数器,记录某操作的次数等。命令:INCRBY

  4、当作简单的队列使用,如消息队列等。

  5、查询最新列表

  6、做排行榜

 

三、ubuntu上安装和卸载redis

  1、离线安装

   ①redis.io下载安装包redis-4.0.10.tar.gz

   ②使用winSCP上传到服务器

   ③解压缩文件得到redis-4.0.10文件夹

      ④进入redis-4.0.10文件夹,使用make和make install 命令安装redis 

 

  2.在线安装

   ①用wget http://download.redis.io/releases/redis-4.0.10.tar.gz 命令获取redis安装包,然后像离线方式一样去安装。

   ②用sudo apt-get install redis-server来自动安装redis,不建议这种方式,有可能不是最新的版本。这种方式下redis执行文件在/usr/bin目录下

   

  3.卸载redis

   ①卸载redis    apt-get remove redis

   ②清除配置     apt-get remove --purge redis

   ③删除usr/local/bin中的redis相关执行文件(手动下载安装包安装)

     ④ 删除 /usr/bin 中的redis相关执行文件(自动安装)

   ⑤删除  /var/log/redis  下的redis日志文件

   ⑥删除 /var/lib/redis/ 下的文件

   ⑦删除 /etc/redis/ 下的内容

 

四、redis的启动、重启与关闭

   ①启动:

    可以先将redis.conf文件复制一份出来修改,然后执行复制出来的配置文件,这样比较保险,以免改错配置文件

    修改修改复制出来的redis.conf,将daemonize  no 改为yes,否则启动后无法执行命令行

      执行命令redis-server redis.conf 来启动redis,使用redis-cli命令进入命令行后输入ping  返回pong则启动成功,

    如果要显示中文需用命令 redis-cli --raw,如果是启动特定的端口则是redis-cli -p 6380,   redis-cli -h ip -p port

    如果要永久设置redis密码,需修改配置文件requirepass 

   ②重启:

    再次执行redis-server命令就能重启 

   ③关闭

    关闭命令行工具redis-cli shutdown

    关闭redis后台Pkill redis-server

       kill -9 XXX 来杀死进程关闭redis-server

 

五、redis配置文件解析  1 -- 绑定主机IP,默认值为127.0.0.1  2 bind 127.0.0.1

  3 
  4 -- 监听端口,默认为6379 
  5 port 6379
  6 
  7 -- 是否开启保护模式,如果要外网可以访问,则一定要设置为no,并将bind 127.0.0.1 注释掉
8 protected-mode yes 9 10 -- 此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度, 11 -- 当然此值必须不大于Linux系统定义的/proc/sys/net/core/somaxconn值, 12 -- 默认是511,而Linux的默认参数值是128。 13 tcp-backlog 511 14 15 -- 在客户端空闲N秒后关闭连接,如果为0,表示禁用 16 timeout 0 17 18 -- 单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态, 19 避免服务器一直阻塞,默认300秒 20 tcp-keepalive 300 21 22 -- 是否以后台进程的方式运行redis 23 daemonize yes 24 25 26 supervised no 27 28 29 -- 以后台进程方式运行redis,则需要指定pid 文件 30 pidfile /var/run/redis_6379.pid 31 32 -- 指定日志级别 notice | debug | verbose | warning 33 loglevel notice 34 35 -- 指定日志文件名称,如果没有是空字符串,表示redis输出到标准输出 36 logfile "" 37 38 -- 数据库的数量,默认使用的数据库是0,可以通过SELECT命令选择一个 39 databases 16 40 41 -- 是否总是显示logo 42 always-show-logo yes 43 44 -- 设置redis进行数据库镜像的频率 45 -- 900秒内至少1个key值改变(则进行数据库保存--持久化) 46 save 900 1 47 -- 300秒内至少10个key值改变(则进行数据库保存--持久化) 48 save 300 10 49 -- 60秒内至少10000个key值改变(则进行数据库保存--持久化) 50 save 60 10000 51 52 -- 持久化出现错误后,是否依然进行继续进行工作 53 stop-writes-on-bgsave-error yes 54 55 -- 使用压缩rdb文件,rdb文件压缩使用LZF压缩算法, 56 -- yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间 57 rdbcompression yes 58 59 -- 是否校验rdb文件,更有利于文件的容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置。 60 rdbchecksum yes 61 62 -- dbfilenamerdb文件名称 63 dbfilename dump.rdb 64 65 -- dir 数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录 66 dir ./ 67 68 -- 当前redis作为slave时,其master的ip和端口(这个地方的IP要用外网的IP,否则会无法 69 slaveof <masterip> <masterport> 70 71 -- 如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。 72 -- masterauth就是用来配置master的密码,这样可以在连上master后进行认证。 73 masterauth 74 75 -- 当从节点失去连接或者复制正在进行,从节点有2种运行方式: 76 -- yes: 继续响应客户端的请求 77 -- no: 出去INFO和SLAVEOF命令之外的任何请求都会返回一个错误 78 slave-serve-stale-data yes 79 80 -- 从服务器是否只读 81 slave-read-only yes 82 83 84 -- 是否使用socket方式复制数据。 85 -- 目前redis复制提供两种方式,disk和socket。如果新的slave连上来或者重连的slave无法部分同步,就会执行全量同步,master会生成rdb文件。 86 -- 有2种方式: 87 -- disk:master创建一个新的进程把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。 88 -- socket: master创建一个新的进程,直接把rdb文件以socket的方式发给slave 89 -- disk方式的时候,当一个rdb保存的过程中,多个slave都能共享这个rdb文件。socket的方式就的一个个slave顺序复制。在磁盘速度缓慢,网速快的情况下推荐用socket方式。 90 repl-diskless-sync no 91 92 -- 当使用socket复制数据启用的时候,socket复制的延迟时间,如果设置成0表示禁用 93 repl-diskless-sync-delay 5 94 95 96 -- 是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no 97 -- 即使用tcp nodelay。如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。 98 -- 但是这也可能带来数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes。 99 repl-disable-tcp-nodelay no 100 101 -- 从节点优先级 102 slave-priority 100 103 104 105 106 lazyfree-lazy-eviction no 107 lazyfree-lazy-expire no 108 lazyfree-lazy-server-del no 109 slave-lazy-flush no 110 111 -- 是否以appendonly模式作为持久化方式 112 -- 默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。 113 -- 但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性。 114 -- Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。 115 appendonly no 116 117 -- AOF 文件名称 118 appendfilename "appendonly.aof" 119 120 -- aof持久化策略的配置 121 -- no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。 122 -- always表示每次写入都执行fsync,以保证数据同步到磁盘。 123 -- everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。 124 appendfsync everysec 125 126 -- 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间, 127 -- no-appendfsync-on-rewrite字段设置为默认设置为no,如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no, 128 -- 这样对持久化特性来说这是更安全的选择。设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入, 129 -- 默认为no,建议yes。Linux的默认fsync策略是30秒。可能丢失30秒数据。 130 no-appendfsync-on-rewrite no 131 132 133 -- AOF自动重写配置 134 -- 当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候Redis能够调用bgrewriteaof对日志文件进行重写。 135 -- 当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。 136 auto-aof-rewrite-percentage 100 137 138 -- 设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写 139 auto-aof-rewrite-min-size 64mb 140 141 -- 是否redis在启动时可以加载被截断的AOF文件 142 aof-load-truncated yes 143 144 -- 混合 RDB-AOF 持久化格式 145 -- Redis 4.0 新增了 RDB-AOF 混合持久化格式,这是一个可选的功能,在开启了这个功能之后, 146 -- AOF 重写产生的文件将同时包含 RDB 格式的内容和 AOF 格式的内容,其中 RDB 格式的内容用于记录已有的数据, 147 -- 而 AOF 格式的内存则用于记录最近发生了变化的数据, 这样 Redis 就可以同时兼有 RDB 持久化和 AOF 持久化的优点 148 -- —— 既能够快速地生成重写文件, 也能够在出现问题时, 快速地载入数据。 149 aof-use-rdb-preamble no 150 151 -- 集群开关,默认是不开启集群模式 152 cluster-enabled yes 153 154 -- 集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息 155 cluster-config-file 156 157 -- 集群节点相互连接的超时时间 158 cluster-node-timeout 10000 159 160 -- 在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间了,导致数据过于陈旧,这样的slave不应该被提升为master。 161 -- 该参数就是用来判>断slave节点与master断线的时间是否过长。判断方法是: 162 -- 比较slave断开连接的时间和(node-timeout *slave-validity-factor) + repl-ping-slave-period 163 -- 如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10秒,即如果超过310秒slave将不会尝试进行故障转移 164 -- 可能出现由于某主节点失联却没有从节点能顶上的情况,从而导致集群不能正常工作,在这种情况下,只有等到原来的主节点重新回归到集群,集群才恢复运作 165 -- 如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节 166 cluster-slave-validity-factor 10 167 168 -- 当一定比例的键空间没有被覆盖到(就是某一部分的哈希槽没了,有可能是暂时挂了),集群就停止处理任何查询炒作。 169 -- 如果该项设置为no,那么就算请求中只有一部分的键可以被查到,一样可以查询(但是有可能会查不全) 170 cluster-require-full-coverage yes 171 172 -- 主节点需要的最小从节点数,只有达到这个数,主节点失败时,它从节点才会进行迁移 173 cluster-migration-barrier 1 174 175 lua-time-limit 5000 176 177 178 -- 执行时间比slowlog-log-slower-than大的请求记录到slowlog里面,单位是微秒,所以1000000就是1秒。注意,负数时间会禁用慢查询日志,而0则会强制记录所有命令。 179 slowlog-log-slower-than 10000 180 181 -- 当一个新的命令被写进日志的时候,最老的那个记录会被删掉。这个长度没有限制。只要有足够的内存就行。你可以通过 SLOWLOG RESET 来释放内存 182 slowlog-max-len 128 183 184 -- 延迟监控功能是用来监控redis中执行比较缓慢的一些操作,用LATENCY打印redis实例在跑命令时的耗时图表。 185 -- 只记录大于等于下边设置的值的操作。0的话,就是关闭监视。默认延迟监控功能是关闭的,如果你需要打开,也可以通过CONFIG SET命令动态设置。 186 latency-monitor-threshold 0 187 188 189 notify-keyspace-events "" 190 191 -- 数据量小于等于list-max-ziplist-entries用ziplist,大于list-max-ziplist-entries用list 192 list-max-ziplist-size -2 193 194 195 list-compress-depth 0 196 197 -- 数据量小于等于set-max-intset-entries用iniset,大于set-max-intset-entries用set 198 set-max-intset-entries 512 199 200 -- 数据量小于等于zset-max-ziplist-entries用ziplist,大于zset-max-ziplist-entries用zset 201 zset-max-ziplist-entries 128 202 203 -- value大小小于等于zset-max-ziplist-value用ziplist,大于zset-max-ziplist-value用zset 204 zset-max-ziplist-value 64 205 206 -- value大小小于等于hll-sparse-max-bytes使用稀疏数据结构(sparse),大于hll-sparse-max-bytes使用稠密的数据结构(dense) 207 hll-sparse-max-bytes 3000 208 209 -- hash table是一种高效的数据结构,被广泛的用在key-value存储中,Redis的dict其实就是一个典型的hash table实现。 210 -- rehash是在hash table的大小不能满足需求,造成过多hash碰撞后需要进行的扩容hash table的操作,其实通常的做法确实是建立一个额外的hash table, 211 -- 将原来的hash table中的数据在新的数据中进行重新输入,从而生成新的hash表。redis的 rehash包括了lazy rehashing和active rehashing两种方式 212 -- lazy rehashing:在每次对dict进行操作的时候执行一个slot的rehash 213 -- active rehashing:每100ms里面使用1ms时间进行rehash。 214 -- 当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。 215 -- 如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存。 216 activerehashing yes 217 218 -- 参数限制分配的缓冲区的大小,防止内存无节制的分配 219 -- redis server以单进程的方式处理接收到的请求,而redis完成请求有些工作比较慢,比如网络IO和磁盘IO等比较慢的操作。 220 -- redis为了提高处理客户端请求的响应时间,做了很多优化。比如网络io和磁盘io是异步完成、使用后台进程完成bgsave和bgrewriteaof工作,在server端为客户提供读buffer等等。 221 -- client buffer是在server端实现的一个读取缓冲区。redis server在接收到客户端的请求后,把影响结果写入到client buffer中,而不是直接发送给客户端。 222 -- server把结果写入到client buffer中后,继续处理客户端的其他请求。这样异步处理方式使redis server不会因为网络原因阻塞其他请求的处理 223 -- 在客户端与server进行的交互中,每个连接都会与一个buffer关联,此buffer用来队列化亟待被client接受的响应信息. 224 -- 如果client不能及时的消费响应信息,那么buffer将会被不断积压而给server带来内存压力.如果buffer中积压的数据达到阀值,将会导致连接被关闭,buffer被移除." 225 -- 普通客户端 226 client-output-buffer-limit normal 0 0 0 227 -- 从节点作为客户端 228 client-output-buffer-limit slave 256mb 64mb 60 229 -- 发布与订阅的客户端 230 client-output-buffer-limit pubsub 32mb 8mb 60 231 232 -- redis执行任务的频率为1s除以hz 233 -- 默认情况下,“hz”设置为10。当Redis空闲时,提高该值将使用更多的CPU, 234 -- 但同时,当有许多密钥同时到期时,将使Redis响应更灵敏,而超时可以更精确地处理。 235 hz 10 236 237 -- 在AOF重写的时候,如果打开了aof-rewrite-incremental-fsync开关,系统会每32MB执行一次fsync。 238 -- 这对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值 239 aof-rewrite-incremental-fsync yes

 

六、redis命令

  Redis 命令参考

 

七、java操作redis数据库

   1、如果出现拒绝链接的情况,修改配置文件或者查看防火墙

    将配置文件 redis.conf 中 bind 127.0.0.1注释掉,将protected-mode yes 改为no

  2.简单的操作redis

  ①导入jar包  redis-2.9.0.jar,commons-pool2-2.4.2.jar

  ②编写代码 

public class TestRedis {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);//默认端口为6379
        jedis.auth("12345");//设置了redis密码,所以连接的时候需要验证密码
        System.out.println("链接成功");
        System.out.println(jedis.ping());
        System.out.println("====");
        Set<String> keys = jedis.keys("*");
        System.out.println(keys);
        jedis.close();
    }
}

结果:

链接成功
PONG
====
[aa, bb, cc, dd, qq, set, set2, myname, 80074567, kyle, sortset, name, age]

 

    ③使用连接池来操作redis

public static void main(String[] args) {

        JedisPoolConfig config = new JedisPoolConfig(); // 连接池的配置对象
        config.setMaxTotal(100); // 设置最大连接数
        config.setMaxIdle(10); // 设置最大空闲连接数
        JedisPool jedisPool = new JedisPool(config,"127.0.0.1");
        Jedis jedis=jedisPool.getResource(); // 获取连接
        jedis.auth("12345"); // 设置密码
        jedis.set("name", "kyle"); // 设置值
        String value=jedis.get("name"); // 获取值
        System.out.println(value);
        jedis.close();
    }

 

八、结合spring框架使用

  ①导包:jedis-2.9.0.jar,commons-pool2-2.4.2.jar,spring-data-redis-1.6.0.RELEASE.jar

  ②配置redis.properties 

#redis服务器ip
redis.hostName=127.0.0.1
#端口
redis.port=6379
#密码
redis.password=12345
#客户端超时时间单位是毫秒
redis.timeout=15000
#是否使用连接池
redis.usePool=true
#缓存过期时间(秒)
redis.expiration=3000
#最大空闲数  
redis.maxIdle=6
#连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal  
redis.maxActive=600  
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性  
redis.maxTotal=1000
#连接的最小空闲时间 默认1800000毫秒(30分钟) 
redis.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目,默认3  
redis.numTestsPerEvictionRun=3
#逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1  
redis.timeBetweenEvictionRunsMillis=60000
#是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个  
redis.testOnBorrow=true  
#在空闲时检查有效性, 默认false  
redis.testWhileIdle=true  

  ③在applicationContext.xml文件中配置redis

<!-- 集成redis -->
     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
      <property name="maxTotal" value="${redis.maxTotal}"></property>
      <property name="maxIdle" value="${redis.maxIdle}"></property>
      <property name="testOnBorrow" value="${redis.testOnBorrow}"></property> 
      <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"></property> 
      <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"></property> 
      <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"></property>
     </bean>
      
     <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> 
      <property name="poolConfig" ref="jedisPoolConfig"></property> 
      <property name="hostName" value="${redis.hostName}"></property> 
      <property name="port" value="${redis.port}"></property> 
      <property name="password" value="${redis.password}"></property> 
      <property name="timeout" value="${redis.timeout}"></property> 
      <property name="usePool" value="${redis.usePool}"></property> 
     </bean>
      
     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
      <property name="connectionFactory" ref="jedisConnectionFactory"></property>
      <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>

 

   ④编写redisCacheUtil工具类,进行处理(下面是简单版,附件中会有详细版,不保证正确)

package com.myproject.utils;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

@Component
public class RedisCacheUtil{

    
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    
    
    public void set(String key,Object value){
        ValueOperations<String,Object> operation = redisTemplate.opsForValue(); 
        operation.set(key,value);
    }
    
    public Object get(String key){
        ValueOperations<String,Object> operation = redisTemplate.opsForValue(); 
        return operation.get(key);
    }
    
    public void setList(String key,List<Object> dataList){
        ListOperations<String, Object> listOperation = redisTemplate.opsForList();
        if (null != dataList && dataList.size() > 0) {
           listOperation.leftPushAll(key, dataList);
        }
    }
    
    public List<Object> getCacheList(String key){
        ListOperations<String,Object> listOperation = redisTemplate.opsForList();
        List<Object> resultList = listOperation.range(key, 0, -1);       
        return resultList;
    }
    
    public void setCacheSet(String key,Set<Object> dataSet){
        BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
        Iterator<Object> it = dataSet.iterator();
        while (it.hasNext()) {
            setOperation.add(it.next());
        }
    }
    
    public Set<Object> getCacheSet(String key){
        BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
        return setOperation.members();
    }
    
    public void setCacheMap(String key,Map<String,Object> dataMap){
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.putAll(key, dataMap);
    }
    
    public Map<String, Object> getCacheMap(String key){
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        return hashOperations.entries(key);
    }
}

 

九、redis的主从复制配置,如果有多个senstinel配置多个senstinel.conf就行

  1、redis的主从复制比较简单,只需要修改redis.conf  中 slaveof  IP port  ,设置为主redis的IP和端口就行。如果是在一台电脑上设置,只需要复制几份redis.conf,并修改对应的端口和pidfile即可。如果主redis设置了密码,则还需要修改从reids的配置文件,设置masterauth 连接密码。但是这样配置实用性不大,当master挂掉之后,slave只能等待master重新启动,不然还是用不了。

  2、使用哨兵sentinel来进行监控就能解决上面提出的问题。Redis提供的sentinel(哨兵)机制,通过sentinel模式启动redis后,自动监控master/slave的运行状态,基本原理是:心跳机制+投票裁决。哨兵会不停的监控着每个redis,如果有服务器出现问题,还可以向管理员发送消息,同时如果master出现问题, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。当以前的master修复后,会变为slave。

  3.配置文件sentinel.conf

 

#Sentinel实例的端口号
port 26379

#Sentinel 实例的目录
dir /tmp

#日志文件
logfile /var/log/redis/redis-server.log

#后台执行
daemonize yes

#3.2里的参数,是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,拒绝外部访问。要是开启了密码   和bind,可以开启。否   则最好关闭,设置为no。
protected-mode no

#格式:sentinel <option_name> <master_name> <option_value>;这一行代表sentinel监控的master的名字叫做mymaster,地址为127.0.0.1:6379,
#行尾最后的一个2代表什么意思呢?我们知道,网络是不可靠的,有时候一个sentinel会因为网络堵塞而误以为一个master redis已经死掉了,
#当sentinel集群式,解决这个问题的方法就变得很简单,只需要多个sentinel互相沟通来确认某个master是否真的死了,
#这个2代表,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。
#就算是在本地也不要用127.0.0.1 ,要用真是的外网能够访问的ip sentinel monitor mymaster
127.0.0.1 6379 1 #sentinel会向master发送心跳PING来确认master是否存活,如果master在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了(subjectively down, 也简称为SDOWN)。 #而这个down-after-milliseconds就是用来指定这个“一定时间范围”的,默认单位是毫秒,默认30秒。 sentinel down-after-milliseconds mymaster 3000 #在发生failover主备切换时,这个选项指定了最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。 #可以通过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态。 sentinel parallel-syncs mymaster 1 #failover过期时间,当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failoer失败。默认180秒,即3minutes. sentinel failover-timeout mymaster 180000 #设置连master和slaves验证密码,如果master和slave设置了密码,则这个也需要设置 #sentinel auth-pass mymaster xxxxxxx #发生切换之后执行的一个自定义脚本:如发邮件、vip切换等 #sentinel notification-script <master-name> <script-path> #发生切换之后执行的一个自定义脚本:如发邮件、vip切换等 #sentinel client-reconfig-script T1 /opt/bin/notify.py

 

  4.spring集成redis 主从和哨兵模式

    ①配置redis.conf

#####################主从配置,如果没有主从,下面的就不需要配置#################################

#sentinel1的IP和端口
sentinel1.host=127.0.0.1
sentinel1.port=26379

###多个sentinel就在下面配置多个
sentinel2.host=127.0.0.1
sentinel2.port=36379

#sentinel的鉴权密码
redis.sentinel.masterName=mymaster
redis.sentinel.password=12345

 

    ②配置applicationContext.xml

<!-- 集成redis -->
     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
      <property name="maxTotal" value="${redis.maxTotal}"></property>
      <property name="maxIdle" value="${redis.maxIdle}"></property>
      <property name="testOnBorrow" value="${redis.testOnBorrow}"></property> 
      <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"></property> 
      <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"></property> 
      <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"></property>
     </bean>
     
     <!--哨兵配置-->
    <bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <property name="master">
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <property name="name" value="${redis.sentinel.masterName}"></property>
            </bean>
        </property>
        <property name="sentinels">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${sentinel1.host}"></constructor-arg>
                    <constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${sentinel2.host}"></constructor-arg>
                    <constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
                </bean>
            </set>
        </property>
    </bean>
      
     <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> 
      <!-- <property name="poolConfig" ref="jedisPoolConfig"></property>  -->
    <!--   <property name="hostName" value="${redis.hostName}"></property> 
      <property name="port" value="${redis.port}"></property> 
      <property name="password" value="${redis.password}"></property>  -->
      <property name="timeout" value="${redis.timeout}"></property> 
      <property name="usePool" value="${redis.usePool}"></property>
      <property name="password" value="${redis.password}"></property>
      <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
     </bean>
      
     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
      <property name="connectionFactory" ref="jedisConnectionFactory"></property>
      <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>

 

十、redis的持久化

  由于redis是基于内存的,所以如果redis重启或者服务器故障数据就会丢失,这就需要将数据持久化。redis现在有两种持久化的方式,分别是RDB和OAF。

  1.RDB:隔一段时间将redis内存中的数据以快照的形式持久化到磁盘上,默认写在dump.rdb文件里。

    在redis.config 文件中配置可以设置什么情况下进行持久化。默认配置如下:

    save 900 1    每900秒,变动1个key,就进行持久化

    save 300 10    每300秒,变动10个key,就进行持久化

    save 60 10000    每60秒,变动10000个key,就进行持久化

  2.AOF:redis每执行的一条命令都追加到到appendonly.aof文件中。AOF默认是不启用的,需要修改redis.conf文件中的appendonly  yes。

十一、redis集群配置

  1、redis.conf中需要额外修改如下配置 (不需要制定slaveof)

cluster-enabled  yes                      //开启集群  把注释#去掉
cluster-config-file  nodes_7000.conf      //集群的配置  配置文件首次启动自动生成 7000,7001,7002
cluster-node-timeout  5000                //请求超时  设置5秒够了

  2.安装ruby,由于scr目录下的edis-trib.rb 无法直接执行,所以需要安装ruby。

  命令:sudo apt-get install ruby, apt-get install rubygems, gem install redis(用 gem 这个命令来安装 redis接口)

  3.启动所有的redis

  4.执行命令:在redis的安装目录的src下,./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:8000 127.0.0.1:8001 127.0.0.1:8002,即可自动完成redis集群和主从的配置

  5.执行上面的命令报错解决办法:

    ①删除node.conf文件,和dump.rdb和appendonly.aof文件。

    ②每个节点flushall清除数据库

    ③每个节点cluster reset 

    ④如果是密码验证的问题,或者无法连接到某个节点,则要修改/var/lib/gems/2.3.0/gems/redis-4.0.1/lib/redis/client.rb文件

  6.为集群添加新的节点

    ①添加主节点,在redis的安装目录的src目录下面执行,./redis-trib.rb  add-node 新添加的节点的IP:port 原集群中的一个节点的IP:port,如./redis-trib.rb add-node 127.0.0.1:9000 127.0.0.1:7000

    ②./redis-trib.rb check 127.0.0.1:7000  (任意一个节点)检查集群的状态,从主和分配的slot等,发现新加入的slot没有分配到slot。

    ③对新加入的主节点分配slot:./redis-trib.rb reshard 127.0.0.1:9000

      How many slots do you want to move (from 1 to 16384)?  输入想要多少节点分配到9000

      What is the receiving node ID?  要接受slot的主节点的id

      Please enter all the source node IDs.  

       Type 'all' to use all the nodes as source nodes for the hash slots.  

      Type 'done' once you entered all the source nodes IDs.  

      Source node #1:all //表示全部节点重新洗牌 ,如果不想重新洗牌则需要输入要移出的节点的nodeid,然后输入done

    ④添加从节点,先按照添加主节点的方式添加一个空节点,然后执行redis-cli -c -p 9001 -a 12345 (访问带密码的redis集群要加上密码,不然重定向会报错)进入新增节点的客户端,执行cluster replicate master-node-id(主节点的id),例如:cluster replicate e2b32349a1e6e7cb9e4776defc4713b12575ee28;

  也可以使用命令 ./redis-trib.rb add-node --slave --master-id e2b32349a1e6e7cb9e4776defc4713b12575ee28 127.0.0.1:9001 127.0.0.1:9000  来执行,参数分别为master的Id、从节点ip和端口、主节点ip和端口。

    ⑤删除从节点 ./redis-trib.rb del-node 127.0.0.1:9001 '7e5ee6d373563d97825a69caee95e6f0e4ed591d'   后面的id为从节点的nodeid

    ⑥删除主节点 如果主节点上分配有slot,那么该节点是无法删除的,必须要先将slot移除。使用命令 ./redis-trib.rb reshard 127.0.0.1:9000

    ⑦钉钉集群中的一些命令

CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。 
//节点
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。 
//键
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。 
//新增
CLUSTER SLAVES node-id 返回一个master节点的slaves 列表

 

    6.spring 集成redis 集群

     

<!-- 集成redis -->
     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
      <property name="maxTotal" value="${redis.maxTotal}"></property>
      <property name="maxIdle" value="${redis.maxIdle}"></property>
      <property name="minIdle" value="${redis.minIdle}"></property>
      <property name="testOnBorrow" value="${redis.testOnBorrow}"></property> 
      <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"></property> 
      <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"></property> 
      <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"></property>
     </bean>
     
    
    <!--配置文件加载-->
    <bean id="resourcePropertySource" class="org.springframework.core.io.support.ResourcePropertySource">
        <constructor-arg name="name" value="redis.properties"/>
        <constructor-arg name="resource" value="classpath:redis.properties"/>
    </bean>
    
    <!-- Redis集群配置     这里使用的是spring-data-redis  包中内容 -->
    <bean id="redisClusterConfig" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <constructor-arg name="propertySource" ref="resourcePropertySource"/>
    </bean>
    
     <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> 
      <property name="poolConfig" ref="jedisPoolConfig"></property> 
      <!-- <property name="usePool" value="${redis.usePool}"></property> -->
      <constructor-arg name="clusterConfig" ref="redisClusterConfig" />
      <property name="password" value="${spring.redis.cluster.password}" />
      
     </bean>
      
     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
      <property name="connectionFactory" ref="jedisConnectionFactory"></property>
      <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>
####################集群配置###########################################################
spring.redis.cluster.nodes=111.230.239.152:7000,111.230.239.152:7001,111.230.239.152:7002,111.230.239.152:8000,111.230.239.152:8001,111.230.239.152:8002
spring.redis.cluster.password=12345
spring.redis.cluster.max-redirects=3
spring.redis.cluster.timeout=5

 

完整版redisCacheUtil

package com.myproject.utils;

import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Component;

@Component
public class RedisCacheUtil {
    
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    
    
    /**
     * @Title: exists
     * @Description: 判断key是否存在
     * @param @param key
     * @return void
      */
     public boolean exists(String key){
         return redisTemplate.hasKey(key);
     }
     
     /**
     * @Title: deleteKey
     * @Description: 删除keys
     * @param @param keys
      */
     public void deleteKey(String... keys){
         List<String> keyList = Arrays.asList(keys);
         redisTemplate.delete(keyList);
     }
     
     /**
     * @Title: expire
     * @Description: 设置key的有效期
     * @param @param key
     * @return boolean
      */
     public boolean expire(String key,long seconds){
         return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
     }
     
     /**
      * @Title: expire
      * @Description: 设置key的有效期
      * @param @param key
      * @return boolean
     */
     public boolean expire(String key,long timeout , TimeUnit timeUnit){
         return redisTemplate.expire(key, timeout, timeUnit);
     }
     
     /**
      * 
     * @Title: expire
     * @Description: 设置key的有效期
     * @param @param key
     * @param @param date
     * @return boolean
      */
     public boolean expire(String key,Date date){
         return redisTemplate.expireAt(key, date);
     }
     
     /**
      * 
     * @Title: getExpire
     * @Description: 获取过期时间(秒)
     * @param @param key
     * @return Long
      */
     public Long getExpire(String key){
         return redisTemplate.getExpire(key);
     }
     
     /**
      * 
     * @Title: getExpire
     * @Description: 获取过期时间(毫秒)
     * @param @param key
     * @param @param timeUnit
     * @return Long
      */
     public Long getExpireMilliSeconds(String key){
         return redisTemplate.getExpire(key,TimeUnit.MILLISECONDS);
     }
     
     /**
      * 
     * @Title: persist
     * @Description: 将key设置为永不失效
     * @param @param key
     * @param @return
     * @return boolean
     * @throws 
      */
     public boolean persist(String key){
         return redisTemplate.persist(key);
     }
     
     /**
     * @Title: keys
     * @Description: 查找符合标准的key
     * @param @param pattern
     * @return Set<String>
      */
     public Set<String> keys(String pattern){
         return redisTemplate.keys(pattern);
     }
     
     /**
      * 
     * @Title: randomKey
     * @Description: 随机返回一个key
     * @param @return
     * @return String
     * @throws 
      */
     public String randomKey(){
         return redisTemplate.randomKey();
     }
     
     /**
      * 
     * @Title: renameKey
     * @Description: 重命名key
     * @param @param oldKey
     * @param @param newKey
     * @return void
     * @throws 
      */
     public void renameKey(String oldKey, String newKey){
         redisTemplate.renameIfAbsent(oldKey, newKey);
     }
     
     /**
      * 缓存基本的对象,Integer、String、实体类等
      * @param key 缓存的键值
      * @param value 缓存的值
      * @return 
      */
     public void psetEX(String key, Object value, long timeout,TimeUnit timeUnit) {
         if(value != null ){
             ValueOperations<String, Object> operation = redisTemplate.opsForValue();
             operation.set(key, value,timeout,timeUnit);
         }
     }
     
     /**
      * 缓存基本的对象,Integer、String、实体类等
      * @param key 缓存的键值
      * @param value 缓存的值
      * @return 
      */
     public void setEx(String key, Object value, long seconds) {
         psetEX(key,value,seconds,TimeUnit.SECONDS);
     }
     
     /**
      * 缓存基本的对象,Integer、String、实体类等,永不失效
      * @param key 缓存的键值
      * @param value 缓存的值
      * @return 
      */
     public void set(String key, Object value) {
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         operation.set(key, value);
     }
     
     /**
      * 
     * @Title: setIfAbsent
     * @Description: 当key不存在时,设置key的值为value
     * @param @param key
     * @param @param value
     * @return void
     * @throws 
      */
     public void setIfAbsent(String key, Object obj) {
         if(obj != null ){
             ValueOperations<String, Object> operation = redisTemplate.opsForValue();
             operation.setIfAbsent(key, obj);
         }
     }
     
     /**
      * 
     * @Title: setRange
     * @Description: 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。
     *               不存在的 key 当作空白字符串处理。如果给定 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ),
     *               那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )来填充
     * @param @param key
     * @param @param value
     * @param @param offset
     * @return void
     * @throws 
      */
     public void setRange(String key, Object value,long offset) {
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         operation.set(key, value, offset);
     }
     
     /**
      * 
     * @Title: setBit
     * @Description: 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
                                                          位的设置或清除取决于 value 参数,可以是 0(false) 也可以是 1(true) 。
     * @param @param key
     * @param @param value
     * @param @param offset
     * @return void
     * @throws 
      */
     public void setBit(String key, boolean value,long offset){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         operation.setBit(key, offset, value);
     }
     
     /**
      * 
     * @Title: multiSet
     * @Description: 同时设置一个或多个 key-value 对。如果有key存在,则覆盖
     * @param @param map
     * @return void
     * @throws 
      */
     public void multiSet(Map<String,Object> map){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         operation.multiSet(map);
     }
     
     /**
      * 
     * @Title: multiSetIfAbsent
     * @Description: 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
     *               即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作。
     * @param @param map
     * @return void
     * @throws 
      */
     public void multiSetIfAbsent(Map<String,Object> map){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         operation.multiSetIfAbsent(map);
     }
     
     /**
      * 
     * @Title: append
     * @Description: 在key的值后面追加value
     * @param @param key
     * @param @param value
     * @param @return 返回追加后的长度
     * @return int
     * @throws 
      */
     public int append(String key, String value){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         Integer len = operation.append(key, value);
         return len;
     }
     
     /**
      * 
     * @Title: get
     * @Description: 获取String key对应的值
     * @param @param key
     * @param @return
     * @return Object
     * @throws 
      */
     public Object get(String key){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.get(key);
     }
     
     /**
      * 
     * @Title: getRange
     * @Description: 返回 key 中字符串值的子字符串,
     *               字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)
     * @param @param key
     * @param @param start
     * @param @param end
     * @param @return
     * @return String
     * @throws 
      */
     public String getRange(String key, long start, long end){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.get(key, start, end);
     }
     
     /**
      * 
     * @Title: getAndSet
     * @Description: 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
     * @param @param key
     * @param @param newValue
     * @param @return
     * @return Object
     * @throws 
      */
     public Object getAndSet(String key, Object newValue){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.getAndSet(key, newValue);
     }
     /**
      * 
      * @Title: getBit
      * @Description: 对 key 所储存的字符串值,获取指定偏移量上的位(bit),该位上为1则为true
      * @param @param key
      * @param @param offset
      * @param @return
      * @return boolean
      * @throws 
      */
     public boolean getBit(String key, long offset){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.getBit(key, offset);
     }
     
     /**
      * 
     * @Title: mget
     * @Description: 返回所有(一个或多个)给定 key 的值
     * @param @param keys
     * @param @return
     * @return List<Object>
     * @throws 
      */
     public List<Object> mget(List<String> keys){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.multiGet(keys);
     }
     
     /**
      * 
     * @Title: size
     * @Description: 返回 key 所储存的字符串值的长度。
     * @param @param key
     * @param @return
     * @return long
     * @throws 
      */
     public long size(String key){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.size(key);
     }
     
     /**
      * 
     * @Title: incrBy
     * @Description: 将 key 所储存的值加上增量 delta 
     * @param @param key
     * @param @param delta
     * @param @return
     * @return Long
     * @throws 
      */
     public Long incrBy(String key,long delta){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.increment(key, delta);
     }
     
     /**
      * 
     * @Title: incrByFloat
     * @Description: 为 key 中所储存的值加上浮点数增量 delta 。
     * @param @param key
     * @param @param delta
     * @param @return
     * @return Double
     * @throws 
      */
     public Double incrByFloat(String key,double delta){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.increment(key, delta);
     }
     
     /**
      * 
     * @Title: incr
     * @Description: 将 key 中储存的数字值增一
     * @param @param key
     * @param @return
     * @return Long
     * @throws 
      */
     public Long incr(String key){
         ValueOperations<String, Object> operation = redisTemplate.opsForValue();
         return operation.increment(key, 1);
     }
     
     
     /**
      * 
     * @Title: lindex
     * @Description: 返回列表 key 中,下标为 index 的元素
     *               下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
     *               你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推
     * @param @param key
     * @param @param index
     * @param @return
     * @return Object
     * @throws 
      */
     public Object lindex(String key, long index){
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         return listOperation.index(key, index);
     }
     
     /**
      * 
     * @Title: lPop
     * @Description: 移除并返回列表 key 的头元素
     * @param @param key
     * @param @return
     * @return Object
     * @throws 
      */
     public Object lPop(String key){
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         return listOperation.leftPop(key);
     }
     
     /**
      * 
     * @Title: blPop
     * @Description: 阻塞式弹出,有超时时间
     * @param @param key
     * @param @param timeout
     * @param @param timeUnit
     * @param @return
     * @return Object
     * @throws 
      */
     public Object blPop(String key,long timeout, TimeUnit timeUnit){
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         return listOperation.leftPop(key, timeout, timeUnit);
     }
     
     /**
      * 
     * @Title: lInsertBefore
     * @Description: 将值 value 插入到列表 key 当中,位于值 pivot 之前
     * @param @param key
     * @param @param pivot
     * @param @param value
     * @param @return
     * @return Long
     * @throws 
      */
     public Long lInsertBefore(String key, Object pivot, Object value){
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         return listOperation.leftPush(key, pivot, value);
     }
     
     /**
      * 
     * @Title: lInsertAfter
     * @Description: 将值 value 插入到列表 key 当中,位于值 pivot 之后
     * @param @param key
     * @param @param pivot
     * @param @param value
     * @param @return
     * @return Long
     * @throws 
      */
     public Long lInsertAfter(String key, Object pivot, Object value){
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         return listOperation.rightPush(key, pivot, value);
     }
     
     /**
      * 缓存List数据(加入到队列头部)
      * @param key 缓存的键值
      * @param dataList 待缓存的List数据
      * @return 
      */
     public void lPush(String key, List<Object> dataList, long timeout, TimeUnit timeUnit) {
         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
         if (null != dataList && dataList.size() > 0) {
            listOperation.leftPushAll(key, dataList);
         }
         redisTemplate.expire(key, timeout, timeUnit);
     }

    /**
     * 缓存List数据(加入到队列头部)
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 
     */
    public void lPush(String key, List<Object> dataList, long seconds) {
        lPush(key,dataList,seconds,TimeUnit.SECONDS);
    }
    
    /**
     * 缓存List数据(加入到队列头部)
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public void lPush(String key, List<Object> dataList) {
        ListOperations<String, Object> listOperation = redisTemplate.opsForList();
        if (null != dataList && dataList.size() > 0) {
           listOperation.leftPushAll(key, dataList);
        }
    }
    
    /**
     * 
    * @Title: lPush
    * @Description: 缓存List数据(加入到队列头部)
    * @param @param key
    * @param @param timeout
    * @param @param timeUnit
    * @param @param values
    * @return void
    * @throws 
     */
    public void lPush(String key, long timeout, TimeUnit timeUnit, Object... values){
        if(values != null && values.length > 0){
            List<Object> valueList = Arrays.asList(values);
            lPush(key, valueList,timeout,timeUnit);
        }
    }
    
    /**
     * 
    * @Title: lPush
    * @Description: 缓存List数据(加入到队列头部)
    * @param @param key
    * @param @param timeout
    * @param @param timeUnit
    * @param @param values
    * @return void
    * @throws 
     */
    public void lPush(String key, long seconds, Object... values){
        lPush(key, seconds, TimeUnit.SECONDS, values);
    }
    
    /**
     * 
    * @Title: lpush
    * @Description: 缓存List数据(加入到队列头部)
    * @param @param key
    * @param @param values
    * @return void
    * @throws 
     */
    public void lPush(String key, Object... values){
        ListOperations<String, Object> listOperation = redisTemplate.opsForList();
        listOperation.leftPushAll(key, values);
    }
    
    /**
     * 
    * @Title: lPushX
    * @Description: 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表
    * @param @param key
    * @param @param value
    * @return void
    * @throws 
     */
    public void lPushX(String key, Object value){
        ListOperations<String, Object> listOperation = redisTemplate.opsForList();
        listOperation.leftPushIfPresent(key, value);
    }
    
    
    /**
     * 缓存List数据(加入到队列尾部)
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 
     */
    public void rPush(String key, List<Object> dataList, long timeout, TimeUnit timeUnit) {
        ListOperations<String, Object> listOperation = redisTemplate.opsForList();
        if (null != dataList && dataList.size() > 0) {
           listOperation.rightPushAll(key, dataList);
        }
        redisTemplate.expire(key, timeout, timeUnit);
    }

   /**
    * 缓存List数据(加入到队列尾部)
    * @param key 缓存的键值
    * @param dataList 待缓存的List数据
    * @return 
    */
   public void rPush(String key, List<Object> dataList, long seconds) {
       rPush(key,dataList,seconds,TimeUnit.SECONDS);
   }
   
   /**
    * 缓存List数据(加入到队列尾部)
    * @param key 缓存的键值
    * @param dataList 待缓存的List数据
    * @return 缓存的对象
    */
   public void rPush(String key, List<Object> dataList) {
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       if (null != dataList && dataList.size() > 0) {
          listOperation.rightPushAll(key, dataList);
       }
   }
   
   /**
    * 
   * @Title: rPush
   * @Description: 缓存List数据(加入到队列尾部)
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @return void
   * @throws 
    */
   public void rPush(String key, long timeout, TimeUnit timeUnit, Object... values){
       if(values != null && values.length > 0){
           List<Object> valueList = Arrays.asList(values);
           rPush(key, valueList,timeout,timeUnit);
       }
   }
   
   /**
    * 
   * @Title: rPush
   * @Description: 缓存List数据(加入到队列尾部)
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @return void
   * @throws 
    */
   public void rPush(String key, long seconds, Object... values){
       rPush(key, seconds, TimeUnit.SECONDS, values);
   }
   
   /**
    * 
   * @Title: rPush
   * @Description: 缓存List数据(加入到队列尾部)
   * @param @param key
   * @param @param values
   * @return void
   * @throws 
    */
   public void rPush(String key, Object... values){
       if(values != null && values.length > 0){
           List<Object> valueList = Arrays.asList(values);
           rPush(key, valueList);
       }
   }
   
   /**
    * 
   * @Title: rPushX
   * @Description: 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表
   * @param @param key
   * @param @param value
   * @return void
   * @throws 
    */
   public void rPushX(String key, Object value){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       listOperation.rightPushIfPresent(key, value);
   }
    
   /**
    * 
   * @Title: rPop
   * @Description:弹出list尾部的一个数据
   * @param @param key
   * @param @return
   * @return Object
   * @throws 
    */
   public Object rPop(String key){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.rightPop(key);
   }
   
   /**
    * 
   * @Title: brPop
   * @Description:阻塞式弹出list中尾部的一个value
   * @param @param key
   * @param @return
   * @return Object
   * @throws 
    */
   public Object brPop(String key, long timeout, TimeUnit timeUnit){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.rightPop(key, timeout, timeUnit);
   }
   
   /**
    * 
   * @Title: rPopLPush
   * @Description: 从原list中弹出最后一个元素,然后加入到目标list头部
   * @param @param sourceKey
   * @param @param destinationKey
   * @param @return
   * @return Object
   * @throws 
    */
   public Object rPopLPush(String sourceKey, String destinationKey){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.rightPopAndLeftPush(sourceKey, destinationKey);
   }
   
   /**
    * 
   * @Title: brPopLPush
   * @Description: 从原list中弹出最后一个元素,然后加入到目标list头部(阻塞式)
   * @param @param sourceKey
   * @param @param destinationKey
   * @param @param timeout
   * @param @param timeUnit
   * @param @return
   * @return Object
   * @throws 
    */
   public Object brPopLPush(String sourceKey, String destinationKey, long timeout, TimeUnit timeUnit){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.rightPopAndLeftPush(sourceKey, destinationKey, timeout, timeUnit);
   }
   
   /**
    * 
   * @Title: lRange
   * @Description: 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
   *               下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推
   * @param @param key
   * @param @param start
   * @param @param end
   * @param @return
   * @return List<Object>
   * @throws 
    */
   public List<Object> lRange(String key, long start, long end){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.range(key, start, end);
   }
   
   /**
    * 
   * @Title: remove
   * @Description: 根据参数 count 的值,移除列表中与参数 value 相等的元素。
                   count 的值可以是以下几种:
                       count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
                       count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
                       count = 0 : 移除表中所有与 value 相等的值。
   * @param @param key
   * @param @param i
   * @param @param value
   * @param @return
   * @return Object
   * @throws 
    */
   public long remove(String key, long i, Object value){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.remove(key, i, value);
   }
   
   /**
    * 
   * @Title: lSet
   * @Description: 将列表 key 下标为 index 的元素的值设置为 value 
   * @param @param key
   * @param @param index
   * @param @param value
   * @return void
   * @throws 
    */
   public void lSet(String key, long index, Object value){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       listOperation.set(key, index, value);
   }
   
   /**
    * 
   * @Title: lTrim
   * @Description: 对一个列表进行修剪(trim),让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除(包头包尾)
   * @param @param key
   * @param @param start
   * @param @param end
   * @return void
   * @throws 
    */
   public void lTrim(String key, long start, long end){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       listOperation.trim(key, start, end);
   }
   
   /**
    * 
   * @Title: llen
   * @Description:返回列表 key 的长度。
   * @param @param key
   * @param @return
   * @return long
   * @throws 
    */
   public long llen(String key){
       ListOperations<String, Object> listOperation = redisTemplate.opsForList();
       return listOperation.size(key);
   }
   
   /**
    * 
   * @Title: sAdd
   * @Description: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @param @return
   * @return long
   * @throws 
    */
   public long sAdd(String key ,long timeout, TimeUnit timeUnit, Object... values){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.expire(timeout, timeUnit);
       return setOperation.add(values);
   }
   
   /**
    * 
   * @Title: sAdd
   * @Description: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @param @return
   * @return long
   * @throws 
    */
   public long sAdd(String key,long seconds, Object... values){
       return sAdd(key,seconds,TimeUnit.SECONDS,values);
   }
   
   /**
    * 
   * @Title: sAdd
   * @Description: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @param @return
   * @return long
   * @throws 
    */
   public long sAdd(String key,Object... values){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.add(values);
   }
   
   /**
    * 缓存Set
    * @param key 缓存键值
    * @param dataSet 缓存的数据
    * @return 缓存数据的对象
    */
   public void sAdd(String key, Set<Object> dataSet, long timeout, TimeUnit timeUnit) {
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.expire(timeout, timeUnit);
       Iterator<Object> it = dataSet.iterator();
       while (it.hasNext()) {
           setOperation.add(it.next());
       }
   }
   
   /**
    * 缓存Set
    * @param key 缓存键值
    * @param dataSet 缓存的数据
    * @return 缓存数据的对象
    */
   public void sAdd(String key, Set<Object> dataSet, long seconds) {
       sAdd(key,dataSet,seconds,TimeUnit.SECONDS);
   }
   
   /**
    * 缓存Set
    * @param key 缓存键值
    * @param dataSet 缓存的数据
    * @return 缓存数据的对象
    */
   public void sAdd(String key, Set<Object> dataSet) {
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       Iterator<Object> it = dataSet.iterator();
       while (it.hasNext()) {
           setOperation.add(it.next());
       }
   }
    
   /**
    * 
   * @Title: sAdd
   * @Description: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
   * @param @param key
   * @param @param timeout
   * @param @param timeUnit
   * @param @param values
   * @param @return
   * @return long
   * @throws 
    */ 
   public long sAdd(String key,Date date,Object... values){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.expireAt(date);
       return setOperation.add(values);
   } 
   
   /**
    * 
   * @Title: sCard
   * @Description: 返回集合中元素的数量
   * @param @param key
   * @param @return
   * @return long
   * @throws 
    */
   public long sCard(String key){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.size();
   } 
    
   /**
    * 
   * @Title: sDiff
   * @Description: 返回该集合是所有给定集合之间的差集,key中有而key2中没有的的元素
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sDiff(String key,String key2){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.diff(key2);
   }
   
   /**
    * 
   * @Title: sDiff
   * @Description: 返回该集合是所有给定集合之间的差集,key中有而keys中没有的的元素
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sDiff(String key,List<String> keys){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.diff(keys);
   }
   
   /**
    * 
   * @Title: sDiff
   * @Description: 将该集合是所有给定集合之间的差集,key中有而key2中没有的的元素,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sDiffStore(String key, String key2, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.diffAndStore(key2, destKey);
   }
   
   /**
    * 
   * @Title: sDiff
   * @Description: 将该集合是所有给定集合之间的差集,key中有而keys中没有的的元素,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sDiffStore(String key, List<String> keys, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.diffAndStore(keys, destKey);
   }
   
   /**
    * 
   * @Title: sInter
   * @Description: 返回该集合是所有给定集合之间的交集
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sInter(String key,String key2){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.diff(key2);
   }
   
   /**
    * 
   * @Title: sInter
   * @Description: 返回该集合是所有给定集合之间的交集
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sInter(String key,List<String> keys){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.diff(keys);
   }
   
   /**
    * 
   * @Title: sInter
   * @Description: 将该集合是所有给定集合之间的交集,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sInterStore(String key, String key2, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.diffAndStore(key2, destKey);
   }
   
   /**
    * 
   * @Title: sInter
   * @Description: 将该集合是所有给定集合之间的交集,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sInterStore(String key, List<String> keys, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.diffAndStore(keys, destKey);
   }
   
   /**
    * 
   * @Title: sUnion
   * @Description: 返回该集合是所有给定集合之间的并集
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sUnion(String key,String key2){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.union(key2);
   }
   
   /**
    * 
   * @Title: sUnion
   * @Description: 返回该集合是所有给定集合之间的并集
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sUnion(String key,List<String> keys){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.union(keys);
   }
   
   /**
    * 
   * @Title: sUnion
   * @Description: 将该集合是所有给定集合之间的并集,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sUnionStore(String key, String key2, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.unionAndStore(key2, destKey);
   }
   
   /**
    * 
   * @Title: sUnion
   * @Description: 将该集合是所有给定集合之间的并集,放入目标set中
   * @param @param key
   * @param @param key2
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public void sUnionStore(String key, List<String> keys, String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       setOperation.unionAndStore(keys, destKey);
   }
    
   /**
    *  
   * @Title: sIsMember
   * @Description: 判断是否为该集合的元素
   * @param @param key
   * @param @param obj
   * @param @return
   * @return boolean
   * @throws 
    */
   public boolean sIsMember(String key, Object obj){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.isMember(obj);
   } 
   
   /**
    * 
   * @Title: sMembers
   * @Description:返回集合 key 中的所有成员。
   * @param @param key
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sMembers(String key){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.members();
   }
    
   /**
    * 
   * @Title: sMove
   * @Description: 将一个元素从一个集合移入另一个集合
   * @param @param key
   * @param @param destKey
   * @param @return
   * @return boolean
   * @throws 
    */
   public boolean sMove(String key,String destKey){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.move(key,destKey);
   } 
    
   /**
    * 
   * @Title: sPop
   * @Description: 随机移除并返回集合中的一个元素
   * @param @param key
   * @param @return
   * @return Object
   * @throws 
    */
   public Object sPop(String key){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.pop();
   } 
    
   /**
    * 
   * @Title: sRem
   * @Description: 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略
   * @param @param obj
   * @param @return
   * @return long
   * @throws 
    */
   public long sRem(String key, Object... obj){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.remove(obj);
   }
   
   /**
    * 
   * @Title: sRandomMembers
   * @Description: 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count个元素的List,数组中的元素可以相同。
   *               如果 count 大于等于集合基数,那么返回整个集合。
   * @param @param key
   * @param @param count
   * @param @return
   * @return List<Object>
   * @throws 
    */
   public List<Object> sRandomMembers(String key, long count){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.randomMembers(count);
   }
   
   /**
    * 
   * @Title: sDistinctRandomMembers
   * @Description: 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的Set,数组中的元素各不相同。
   *               如果 count 大于等于集合基数,那么返回整个集合。
   * @param @param key
   * @param @param count
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> sDistinctRandomMembers(String key, long count){
       BoundSetOperations<String, Object> setOperation = redisTemplate.boundSetOps(key);
       return setOperation.distinctRandomMembers(count);
   }


   /**
    * 
   * @Title: hSet
   * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
   * @param @param key
   * @param @param hashKey
   * @param @param value
   * @param @param timeout
   * @param @param timeUnit
   * @return void
   * @throws 
    */
   public void hSet(String key, String hashKey, Object value, long timeout ,TimeUnit timeUnit){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.put(key, hashKey, value);
       redisTemplate.expire(key, timeout, timeUnit);
   }
   
   /**
    * 
    * @Title: hSet
    * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
    * @param @param key
    * @param @param hashKey
    * @param @param value
    * @param @param timeout
    * @param @param timeUnit
    * @return void
    * @throws 
    */
   public void hSet(String key, String hashKey, Object value, long seconds){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.put(key, hashKey, value);
       redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
   }
   
   /**
    * 
    * @Title: hSet
    * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
    * @param @param key
    * @param @param hashKey
    * @param @param value
    * @param @param timeout
    * @param @param timeUnit
    * @return void
    * @throws 
    */
   public void hSet(String key, String hashKey, Object value){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.put(key, hashKey, value);
   }
   
   /**
    * 
   * @Title: hmSet
   * @Description:  批量为Hash赋值
   * @param @param key
   * @param @param map
   * @param @param timeout
   * @param @param timeUnit
   * @return void
   * @throws 
    */
   public void hmSet(String key, Map<String,Object> map, long timeout ,TimeUnit timeUnit){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putAll(key, map);
       redisTemplate.expire(key, timeout, timeUnit);
   }
   
   /**
    * 
   * @Title: hmSet
   * @Description:  批量为Hash赋值
   * @param @param key
   * @param @param map
   * @param @param timeout
   * @param @param timeUnit
   * @return void
   * @throws 
    */
   public void hmSet(String key, Map<String,Object> map, long second){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putAll(key, map);
       redisTemplate.expire(key, second, TimeUnit.SECONDS);
   }
   
   /**
    * 
   * @Title: hmSet
   * @Description:  批量为Hash赋值
   * @param @param key
   * @param @param map
   * @param @param timeout
   * @param @param timeUnit
   * @return void
   * @throws 
    */
   public void hmSet(String key, Map<String,Object> map){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putAll(key, map);
   }
   
   /**
    * 
   * @Title: hSetNx
   * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
   * @param @param key
   * @param @param hashKey
   * @param @param value
   * @param @param timeout
   * @param @param timeUnit
   * @return void
   * @throws 
    */
   public void hSetNx(String key, String hashKey, Object value, long timeout ,TimeUnit timeUnit){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putIfAbsent(key, hashKey, value);
       redisTemplate.expire(key, timeout, timeUnit);
   }
   
   /**
    * 
    * @Title: hSet
    * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
    * @param @param key
    * @param @param hashKey
    * @param @param value
    * @param @param timeout
    * @param @param timeUnit
    * @return void
    * @throws 
    */
   public void hSetNx(String key, String hashKey, Object value, long seconds){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putIfAbsent(key, hashKey, value);
       redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
   }
   
   /**
    * 
    * @Title: hSetNx
    * @Description: 将哈希表 key 中的域 hashKey 的值设为 value 
    * @param @param key
    * @param @param hashKey
    * @param @param value
    * @param @param timeout
    * @param @param timeUnit
    * @return void
    * @throws 
    */
   public void hSetNx(String key, String hashKey, Object value){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.putIfAbsent(key, hashKey, value);
   }
   
   /**
    * 
   * @Title: hGet
   * @Description: 返回哈希表 key 中给定域 hashKey 的值
   * @param @param key
   * @param @param hashKey
   * @param @return
   * @return Object
   * @throws 
    */
   public Object hGet(String key, String hashKey){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.get(key, hashKey);
   }
   
   /**
    * 
   * @Title: hmGet
   * @Description: 返回哈希表 key 中给定域 hashKey 的值(多个)
   * @param @param key
   * @param @param hashKeys
   * @param @return
   * @return List<Object>
   * @throws 
    */
   public List<Object> hmGet(String key, List<String> hashKeys){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.multiGet(key, hashKeys);
   }
   
   /**
    * 
   * @Title: hGetAll
   * @Description: 返回哈希表 key 中,所有的域和值
   * @param @param key
   * @param @return
   * @return Map<String,Object>
   * @throws 
    */
   public Map<String, Object> hGetAll(String key){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.entries(key);
   }
   
   /**
    * 
   * @Title: hKeys
   * @Description: 返回hash的所有hashKey
   * @param @param key
   * @param @return
   * @return Set<String>
   * @throws 
    */
   public Set<String> hKeys(String key){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.keys(key);
   }
   
   /**
    * 
   * @Title: hVals
   * @Description: 返回hash的所有value
   * @param @param key
   * @param @return
   * @return Set<String>
   * @throws 
    */
   public List<Object> hVals(String key){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.values(key);
   }
   
   /**
    * 
   * @Title: hLen
   * @Description: 返回哈希表 key 中域的数量
   * @param @param key
   * @param @return
   * @return long
   * @throws 
    */
   public long hLen(String key){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.size(key);
   }
   
   /**
    * 
   * @Title: hExists
   * @Description: 判断hash中是否有该hashKey
   * @param @param key
   * @param @param hashKey
   * @param @return
   * @return boolean
   * @throws 
    */
   public boolean hExists(String key, String hashKey){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       return hashOperations.hasKey(key,hashKey);
   } 
   
   /**
    * 
   * @Title: hDel
   * @Description: 删除hash中的hashKey
   * @param @param key
   * @param @param hashKey
   * @return void
   * @throws 
    */
   public void hDel(String key, String hashKey){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.delete(key,hashKey);
   }
   
   /**
    * 
   * @Title: hIncrBy
   * @Description: 为哈希表 key 中的域 field 的值加上增量 delta
   * @param @param key
   * @param @param hashKey
   * @param @param delta
   * @return void
   * @throws 
    */
   public void hIncrBy(String key,String hashKey, long delta){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.increment(key,hashKey,delta);
   }
   
   /**
    * 
   * @Title: hIncrByFloat
   * @Description:  为哈希表 key 中的域 field 的值加上增量 delta
   * @param @param key
   * @param @param hashKey
   * @param @param delta
   * @return void
   * @throws 
    */
   public void hIncrByFloat(String key,String hashKey, double delta){
       HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
       hashOperations.increment(key,hashKey,delta);
   }
   
   
   /**
    * 
   * @Title: zadd
   * @Description: 将一个元素及其 score 值加入到有序集 key 当中
   * @param @param key
   * @param @param obj
   * @param @param score
   * @return void
   * @throws 
    */
   public void zadd(String key , Object obj, double score){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.add(obj,score);
   }
   
   
   /**
    * 
   * @Title: zadd
   * @Description: 将一个或多个元素及其 score 值加入到有序集 key 当中。
   * @param @param key
   * @param @param list
   * @return void
   * @throws 
    */
   public void zadd(String key,List<Object> list){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       Set<TypedTuple<Object>> tuples = new HashSet<TypedTuple<Object>>();
       double score = 0;
       for(Object obj : list){
           TypedTuple<Object> tuple = new DefaultTypedTuple<Object>(obj, score);
           score ++;
           tuples.add(tuple);
       }
       boundZSetOps.add(tuples);
   }
   
   /**
    * 
   * @Title: zCard
   * @Description:返回有序集 key 的基数(集合的大小)
   * @param @param key
   * @param @return
   * @return long
   * @throws 
    */
   public long zCard(String key){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.zCard();
   }
   
   /**
    * 
   * @Title: zCount
   * @Description: 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
   * @param @param key
   * @param @param min
   * @param @param max
   * @param @return
   * @return long
   * @throws 
    */
   public long zCount(String key, double min, double max){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.count(min, max);
   }
   
   /**
    * 
   * @Title: zIncrBy
   * @Description: 为有序集 key 的成员 member 的 score 值加上增量 increment
   * @param @param key
   * @param @param obj
   * @param @param increment
   * @return void
   * @throws 
    */
   public void zIncrBy(String key, Object obj, double increment){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.incrementScore(obj, increment);
   }
   
   /**
    * 
   * @Title: zRange
   * @Description: 返回有序集 key 中,指定区间内的成员,其中成员的位置按 score 值递增(从小到大)来排序。
   * @param @param key
   * @param @param start
   * @param @param end
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> zRange(String key, long start, long end){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.range(start, end);
   }
   
   /**
    * 
   * @Title: zRangeWithScores
   * @Description: 返回有序集 key 中,指定区间内的成员(包含score)
   * @param @param key
   * @param @param start
   * @param @param end
   * @param @return
   * @return Set<TypedTuple<Object>>
   * @throws 
    */
   public Set<TypedTuple<Object>> zRangeWithScores(String key, long start, long end){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.rangeWithScores(start, end);
   }
   
   /**
    * 
   * @Title: zRangeByScore
   * @Description: 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
   * @param @param key
   * @param @param min
   * @param @param max
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> zRangeByScore(String key, double min, double max){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.rangeByScore(min, max);
   }
   
   /**
    * 
   * @Title: zRangeByScoreWithScores
   * @Description: 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。(包含score)
   * @param @param key
   * @param @param min
   * @param @param max
   * @param @return
   * @return Set<TypedTuple<Object>>
   * @throws 
    */
   public Set<TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.rangeByScoreWithScores(min, max);
   }
   
   /**
    * 
   * @Title: zRank
   * @Description: 返回有序集 key 中成员obj的排名,其中有序集成员按 score 值递增(从小到大)顺序排列。排名以 0 为底,也就是说, score 值最小的成员排名为 0 
   * @param @param key
   * @param @param obj
   * @param @return
   * @return Object
   * @throws 
    */
   public Object zRank(String key, Object obj){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.rank(obj);
   }
   
   /**
    * 
   * @Title: zRem
   * @Description: 移除一个或者多个成员
   * @param @param key
   * @param @param obj
   * @param @return
   * @return long
   * @throws 
    */
   public long zRem(String key, Object... obj){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.remove(obj);
   }
   
   /**
    * 
   * @Title: zRemRangeByRank
   * @Description: 移除有序集 key 中,指定排名(rank)区间内的所有成员
   *               下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
                                                    你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推
   * @param @param key
   * @param @param start
   * @param @param end
   * @return void
   * @throws 
    */
   public void zRemRangeByRank(String key, long start, long end ){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.removeRange(start, end);
   }
   
   /**
    * 
   * @Title: zRemRangeByScore
   * @Description: 移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员
   * @param @param key
   * @param @param min
   * @param @param max
   * @return void
   * @throws 
    */
   public void zRemRangeByScore(String key, double min, double max ){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.removeRangeByScore(min, max);
   }
   
   /**
    * 
   * @Title: zRevRange
   * @Description: 返回有序集 key 中,指定区间内的成员。
   *               其中成员的位置按 score 值递减(从大到小)来排列。
   * @param @param key
   * @param @param start
   * @param @param end
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> zRevRange(String key, long start, long end){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.reverseRange(start, end);
   }
   
   /**
    * 
   * @Title: zRevRangeByScore
   * @Description: 返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。
   *               有序集成员按 score 值递减(从大到小)的次序排列。
   * @param @param key
   * @param @param min
   * @param @param max
   * @param @return
   * @return Set<Object>
   * @throws 
    */
   public Set<Object> zRevRangeByScore(String key, double min, double max){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.reverseRangeByScore(min, max);
   }
   
   /**
    * 
   * @Title: zRevRangeWithScores
   * @Description: 返回有序集 key 中,指定区间内的成员包含scores。
   *               其中成员的位置按 score 值递减(从大到小)来排列。
   * @param @param key
   * @param @param start
   * @param @param end
   * @param @return
   * @return Set<TypedTuple<Object>>
   * @throws 
    */
   public Set<TypedTuple<Object>> zRevRangeWithScores(String key, long start, long end){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.reverseRangeWithScores(start, end);
   }
   
   /**
    * 
   * @Title: zRevRangeByScoreWithScores
   * @Description: 返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员包含scores。
   *               有序集成员按 score 值递减(从大到小)的次序排列。
   * @param @param key
   * @param @param min
   * @param @param max
   * @param @return
   * @return Set<TypedTuple<Object>>
   * @throws 
    */
   public Set<TypedTuple<Object>> zRevRangeByScoreWithScores(String key, double min, double max){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.reverseRangeByScoreWithScores(min, max);
   }
   
   /**
    * 
   * @Title: zRevRange
   * @Description: 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
   *               排名以 0 为底,也就是说, score 值最大的成员排名为 0 。
   * @param @param key
   * @param @param obj
   * @param @return
   * @return long
   * @throws 
    */
   public long zRevRange(String key, Object obj){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.reverseRank(obj);
   }
   
   /**
    * 
   * @Title: zScore
   * @Description: 返回有序集 key 中,成员 obj 的 score 值
   * @param @param key
   * @param @param obj
   * @param @return
   * @return double
   * @throws 
    */
   public double zScore(String key, Object obj){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       return boundZSetOps.score(obj);
   }
   
   /**
    * 
   * @Title: zUnionStore
   * @Description: 计算给定的一个或多个有序集的并集
   * @param @param key
   * @param @param otherKeys
   * @param @param destKey
   * @return void
   * @throws 
    */
   public void zUnionStore(String key, List<String> otherKeys, String destKey){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.unionAndStore(otherKeys,destKey);
   }
   
   /**
    * 
   * @Title: zUnionStore
   * @Description: 计算给定的一个或多个有序集的并集
   * @param @param key
   * @param @param otherKey
   * @param @param destKey
   * @return void
   * @throws 
    */
   public void zUnionStore(String key, String otherKey, String destKey){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.unionAndStore(otherKey,destKey);
   }
   
   /**
    * 
   * @Title: zInterStore
   * @Description: 计算给定的一个或多个有序集的交集
   * @param @param key
   * @param @param otherKeys
   * @param @param destKey
   * @return void
   * @throws 
    */
   public void zInterStore(String key, List<String> otherKeys, String destKey){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.unionAndStore(otherKeys,destKey);
   }
   
   /**
    * 
   * @Title: zInterStore
   * @Description: 计算给定的一个或多个有序集的交集
   * @param @param key
   * @param @param otherKey
   * @param @param destKey
   * @return void
   * @throws 
    */
   public void zInterStore(String key, String otherKey, String destKey){
       BoundZSetOperations<String, Object> boundZSetOps = redisTemplate.boundZSetOps(key);
       boundZSetOps.unionAndStore(otherKey,destKey);
   }
}
View Code

 

 

   

posted @ 2018-07-09 09:12  KyleInJava  阅读(785)  评论(0编辑  收藏  举报