IT技术互动交流平台

redis + 主从 + 持久化 + 分片 + 集群 + spring集成

作者:JAVA_攻_城_狮  来源:IT165收集  发布日期:2016-11-15 19:53:39

Redis是一个基于内存的数据库,其不仅读写速度快,每秒可以执行大约110000的写操作,81000的读取操作,而且其支持存储字符串,哈希结构,链表,集合丰富的数据类型。所以得到很多开发者的青睐。加之其支持主从、持久化等功能,3.0版本开始正式提供分片技术、让其在大型互联网应用中大显身手,本文通过实际操作和理论相配合,对redis进行详细地阐述。

一、redis的安装与使用

下载直接去redis的官网http://redis.io/进行不同操作系统对应的版本。本文中采用的redis的版本为3.2.5、linux平台,安装过程如下

[root@hbase usr]# tar -zxf redis-3.2.5.tar.gz 
[root@hbase usr]# cd redis-3.2.5
[root@hbase redis-3.2.5]# ll
[root@hbase redis-3.2.5]# make
[root@hbase redis-3.2.5]# cd src
[root@hbase src]# ll

之后我们会发现其中redis-server和redis-cli,这两个文件分别对应启动redis的服务端和客户端,启动服务端

[root@hbase src]# ./redis-server 
11579:M 13 Nov 15:07:01.399 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.2.5 (00000000/0) 32 bit
  .-`` .-```.  ```/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 11579
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

11579:M 13 Nov 15:07:01.404 # Server started, Redis version 3.2.5
11579:M 13 Nov 15:07:01.409 * The server is now ready to accept connections on port 6379

可以看到,redis正常启动,6379 是 redis 服务端口,这个端口在redis.conf中可以进行配置,稍后我们讲解配置文件的时候会提到。不要关闭这个窗口,因为当前redis-server不是在后台运行,我们另起一个窗口,在当前目录下进行客户端连接服务端。

[hadoop@hbase src]$ ./redis-cli 
127.0.0.1:6379> 

说明一切正常,linux环境下的redis安装成功,至于windows下的安装过程相对更加简单,只需打开.exe文件即可,不在详细演示

二、redis数据类型

2.1 string

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,在Redis中字符串类型的Value最多可以容纳的数据长度是512M。除了get、set、作外,Redis还提供了其他的一些诸如追加、递增等功能。

set key value O(1) 设定该key对应的value,如果该Key已经存在,则覆盖其原有值。get key O(1) 获取指定Key的value,如果该Key不存在,返回nil。

setnx key value O(1) 如果指定的Key不存在,则设定该Key持有指定字符串value,此时其效果等价于set命令。如果该Key已经存在,该命令将不做任何操作。 

 1 127.0.0.1:6379> set hello word
 2 OK
 3 127.0.0.1:6379> get hello
 4 'word'
 5 127.0.0.1:6379> set hello world
 6 OK
 7 127.0.0.1:6379> set hello world
 8 OK
 9 127.0.0.1:6379> get hello
10 'world'
11 127.0.0.1:6379> get world
12 (nil)
13 127.0.0.1:6379> set hello world_new
14 OK
15 127.0.0.1:6379> get hello
16 'world_new'
17 127.0.0.1:6379> setnx hello nihao
18 (integer) 0
19 127.0.0.1:6379> setnx new_hello nihao
20 (integer) 1

mset key value [key value ...] O(N) N表示指定Key的数量。该命令可以看成是多次迭代执行set命令。

mget key [key ...] O(N) N表示获取Key的数量。返回所有指定key的value,如果其中某个key不存在,该key的value将返回nil。 

msetnx key value [key value ...] O(N) N表示指定key的数量。该命令原子性的完成参数中所有key/value的设置操作,其具体行为可以看成是多次迭代执行setnx命令。如果在这一批keys中有任意一个key已经存在,那么该操作将全部回滚,即所有的修改都不会生效。 1表示所有keys都设置成功,0则表示没有任何key被修改。 

 1 127.0.0.1:6379> mset key1 hello key2 world
 2 OK
 3 127.0.0.1:6379> mget key1 key2
 4 1) 'hello'
 5 2) 'world'
 6 127.0.0.1:6379> mget key1 key3
 7 1) 'hello'
 8 2) (nil)
 9 127.0.0.1:6379> msetnx key1 nihao key3 hi
10 (integer) 0
11 127.0.0.1:6379> msetnx key3 nihao key4 hi
12 (integer) 1

append key value  O(1) 若key已经存在,将value的数据追加到对应key的value的末尾。如果该key不存在,append命令将会创建一个新的key/value。

strlen key O(1) 返回指定Key的字符值长度,如果该Key不存在,返回0。

decr key O(1) 将指定key的value原子性的递减1。如果该key不存在,其初始值为0,在decr之后其值为-1。如果value的值不能转换为整型值,该操作将执行失败。

incr key O(1) 将指定key的value原子性的递增1。如果该Key不存在,其初始值为0,在incr之后其值为1。如果value的值不能转换为整型值,该操作将执行失败。 

decrby key decrement O(1) 将指定key的value原子性的减少decrement,其他同decr。

incrby key increment O(1) 将指定key的value原子性的增加increment,其他同incr。 

 1 127.0.0.1:6379> append k1 hello
 2 (integer) 5
 3 127.0.0.1:6379> append k1 world
 4 (integer) 10
 5 127.0.0.1:6379> get k1
 6 'helloworld'
 7 127.0.0.1:6379> strlen k1
 8 (integer) 10
 9 127.0.0.1:6379> set k2 1
10 OK
11 127.0.0.1:6379> incr k2
12 (integer) 2
13 127.0.0.1:6379> get k2
14 '2'
15 127.0.0.1:6379> decr k2
16 (integer) 1
17 127.0.0.1:6379> get k2
18 '1'
19 127.0.0.1:6379> incrby k2 5
20 (integer) 6
21 127.0.0.1:6379> decrby k2 5
22 (integer) 1
23 127.0.0.1:6379> get k2
24 '1'

2.2 redis之数据类型list

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素,该操作也可以在常量时间内完成。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。 

lpush key value [value ...] O(1) 在指定key所对应的List头部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

lpop key O(1) 返回并弹出指定key对应链表的第一个元素。如果该Key不存在,返回nil。

lrange key start stop start和end都是0-len,即0表示链表头部的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。 

lpushx key value O(1) 当指定的key存在时,在其所关联的list的头部插入参数中给出的value,否则将不会有任何操作发生。    

lrem key count value O(N) 在指定key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的key不存在,则直接返回0。

llen key O(1) 返回指定key关联的链表中元素的数量,如果该Key不存在,则返回0。。

lset  key index value O(N) 设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。 

 1 127.0.0.1:6379> lpush k1 v1 v2 v3
 2 (integer) 3
 3 127.0.0.1:6379> lrange k1 0 2
 4 1) 'v3' 2) 'v2' 3) 'v1'
 5 127.0.0.1:6379> lpop k1
 6 'v3'
 7 127.0.0.1:6379> lrange k1 0 2
 8 1) 'v2' 2) 'v1'
 9 127.0.0.1:6379> lpush k1 v4
10 (integer) 3
11 127.0.0.1:6379> lrange k1 0 2
12 1) 'v4' 2) 'v2' 3) 'v1'
13 127.0.0.1:6379> lpush k1 v4
14 (integer) 4
15 127.0.0.1:6379> lpush k1 v4
16 (integer) 5
17 127.0.0.1:6379> lpush k1 v4
18 (integer) 6
19 127.0.0.1:6379> lrange k1 0 5
20 1) 'v4' 2) 'v4' 3) 'v4' 4) 'v4' 5) 'v2' 6) 'v1'
21 127.0.0.1:6379> lrem k1 2 v4  # 删除前两个值为v4的元素
22 (integer) 2
23 127.0.0.1:6379> lrange k1 0 3
24 1) 'v4' 2) 'v4' 3) 'v2' 4) 'v1'
25 127.0.0.1:6379> llen k1
26 (integer) 4
27 127.0.0.1:6379> lset k1 1 k5  #设置索引为1的值为k5
28 OK
29 127.0.0.1:6379> lrange k1 0 3
30 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1'

rpush key value [value ...] O(1) 在指定key所对应的List尾部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

rpop key O(1) 返回并弹出指定key对应链表的最后一个元素。如果该Key不存在,返回nil。

rpushx key value O(1) 当指定的key存在时,在其所关联的list的尾部插入参数中给出的value,否则将不会有任何操作发生。  

 1 127.0.0.1:6379> lrange k1 0 3
 2 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1'
 3 127.0.0.1:6379> rpushx k1 k6
 4 (integer) 5
 5 127.0.0.1:6379> lrange k1 0 4
 6 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6'
 7 127.0.0.1:6379> rpush k1 k7 k8  #在尾部添加元素
 8 (integer) 7
 9 127.0.0.1:6379> lrange k1 0 6
10 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7' 7) 'k8'  
11 127.0.0.1:6379> rpop k1  #弹出尾部的元素
12 'k8'
13 127.0.0.1:6379> lrange k1 0 5
14 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7'
15 127.0.0.1:6379> 

2.3 hash

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。每一个Hash可以存储4294967295个键值对。

hset key field value O(1) 为指定的key设置field/value对,若key不存在,则创建新key,并创建field/value对,若该key中已经存在,则用新值覆盖其原有值。

hget key field O(1) 返回指定key中指定field所对应的值,若key或field不存在,返回nil。

hmget key field [field ...] O(N) 获取指定fields关联的一组values。如果请求的field不存在,其值返回nil。

hmset key field value [field value ...] O(N) 逐个依次设置参数中给出的field/value对。如果其中某个field已经存在,则用新值覆盖原有值。如果key不存在,则创建新key,同时设定参数中的field/value。

hsetnx key field value O(1) 只有当key或field不存在时,为指定的key设定field/value对,否则该命令不会进行任何操作。

 1 127.0.0.1:6379> hset k1 f1 v1
 2 (integer) 1
 3 127.0.0.1:6379> hset k1 f2 v2
 4 (integer) 1
 5 127.0.0.1:6379> hget k1 f1
 6 'v1'
 7 127.0.0.1:6379> hmget k1 f1 f2
 8 1) 'v1' 2) 'v2'
 9 127.0.0.1:6379> hmset k1 f3 v3 f4 v4
10 OK
11 127.0.0.1:6379> hmget k1 f1 f2 f3 f4
12 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4'
13 127.0.0.1:6379> hsetnx k1 f1 v5
14 (integer) 0
15 127.0.0.1:6379> hsetnx k1 f5 v5
16 (integer) 1
17 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 f5
18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5'

hkeys key O(N) 返回指定key的所有fields名。

hvals key O(N) 返回指定Key的所有values名。

hexists key field O(1) 判断指定key中的指定field是否存在。1表示存在,0表示field或key不存在。

hlen key O(1) 获取该key所包含的field的数量。返回key包含的field数量,如果key不存在,返回0。

hdel key field [field ...] O(N) 从指定key的hash中删除指定的多个字段,如果不存在的字段将被忽略。

hincrby key field increment O(1) 增加指定key中指定field对应的value的值。如果key或field不存在,该命令将会创建一个新key或新field。 

 1 127.0.0.1:6379> hkeys k1
 2 1) 'f1' 2) 'f2' 3) 'f3' 4) 'f4' 5) 'f5'
 3 127.0.0.1:6379> hvals k1
 4 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5'
 5 127.0.0.1:6379> hexists k1 f1
 6 (integer) 1
 7 127.0.0.1:6379> hlen k1 
 8 (integer) 5
 9 127.0.0.1:6379> hdel k1 f5
10 (integer) 1
11 127.0.0.1:6379> hset k1 f5 1
12 (integer) 1
13 127.0.0.1:6379> hvals k1
14 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '1'
15 127.0.0.1:6379> hincrby k1 f5 2
16 (integer) 3
17 127.0.0.1:6379> hvals k1
18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '3'

2.4 set

在Redis中, Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。set可包含的最大元素数量是4294967295。set集合中不允许出现重复的元素。 

sadd key member [member ...] O(N) 若该Key不存在,该命令将会创建一个新的set。若有的成员在set中已经存在,该成员将被忽略,而其它成员仍将会被正常插入。

spop key O(1) 随机的移除并返回set中的某一成员。

scard key O(1) 获取set中成员的数量。

sismember key member O(1) 判断参数中指定成员是否已经存在于与key所在的set集合中。

smembers key O(N) 获取与该key关联的set中所有的成员。     

srem key member [member ...] O(N) 从与key关联的set中删除参数中指定的成员,不存在的参数成员将被忽略。

 1 127.0.0.1:6379> sadd k1 m1
 2 (integer) 1
 3 127.0.0.1:6379> sadd k1 m2
 4 (integer) 1
 5 127.0.0.1:6379> scard k1
 6 (integer) 2
 7 127.0.0.1:6379> spop k1
 8 'm2'
 9 127.0.0.1:6379> sadd k1 m3
10 (integer) 1
11 127.0.0.1:6379> sismember k1 m3
12 (integer) 1
13 127.0.0.1:6379> smembers k1
14 1) 'm3'
15 2) 'm1'
16 127.0.0.1:6379> srem k1 m1
17 (integer) 1
18 127.0.0.1:6379> smembers k1
19 1) 'm3'

sdiff key [key ...] O(N) 返回第一个key所关联的set和其后所有keys所关联的sets中成员的差异。

sinter  key [key ...] O(N*M) 返回参数中所有keys关联的sets中成员的交集。

sunion key [key ...] O(N) 返回参数中所有keys关联的sets中成员的并集。  

127.0.0.1:6379> smembers k1
1) 'm2'
2) 'm1'
3) 'm3'
127.0.0.1:6379> smembers k2
1) 'm3'
2) 'm1'
3) 'm4'
127.0.0.1:6379> sdiff k1 k2
1) 'm2'
127.0.0.1:6379> sinter k1 k2
1) 'm1'
2) 'm3'
127.0.0.1:6379> sunion k1 k2
1) 'm3'
2) 'm1'
3) 'm2'
4) 'm4'

 2.5 sorted set

sorted-set和set类型极为相似,都不允许重复的成员出现在一个Set中。它们之间的主要差别是sorted-set中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。

zadd key score member [score] [member] O(log(N)) 添加参数中指定的所有成员及其分数到指定key的sorted-sett中。

zcard key O(1) 获取与该key相关联的sorted-set中包含的成员数量。

zscore key member O(1) 获取指定Key的指定成员的分数。如果该成员存在,以字符串的形式返回其分数,否则返回nil。

zcount key min max O(log(N)+M) 用于获取分数(score)在min和max之间的成员数量。min和max表示的范围是闭区间范围,即min <= score <= max内的成员将被返回。

zincrby key increment member O(log(N)) 将为指定Key中的指定成员增加指定的分数。

zrange key start stop [WITHSCORES] O(log(N)+M)  返回顺序在start和stop指定范围内的成员列表。

zrangebyscore key min max [WITHSCORES] [LIMIT offset count] O(log(N)+M) 将返回分数在min和max之间的所有成员列表。

zrem key member [member ...] O(M log(N)) 移除参数中指定的成员,其中不存在的成员将被忽略。

zremrangebyscore key min max O(log(N)+M) 删除分数在min和max之间的所有成员,即满足表达式min <= score <= max的所有成员。 

 1 127.0.0.1:6379> zadd k1 1 m1
 2 (integer) 1
 3 127.0.0.1:6379> zadd k1 2 m2
 4 (integer) 1
 5 127.0.0.1:6379> zadd k1 3 m3
 6 (integer) 1
 7 127.0.0.1:6379> zcard k1
 8 (integer) 3
 9 127.0.0.1:6379> zscore k1 m1
10 '1'
11 127.0.0.1:6379> zscore k1 m2
12 '2'
13 127.0.0.1:6379> zcount k1 2 3
14 (integer) 2
15 127.0.0.1:6379> zincrby k1 3 m3
16 '6'
17 127.0.0.1:6379> zrange k1 1 10
18 1) 'm2'
19 2) 'm3'
20 127.0.0.1:6379> zrange k1 0 10
21 1) 'm1'
22 2) 'm2'
23 3) 'm3'
24 127.0.0.1:6379> zcount k1 0 10
25 (integer) 3
26 127.0.0.1:6379> zrangebyscore k1 0 6
27 1) 'm1'
28 2) 'm2'
29 3) 'm3'
30 127.0.0.1:6379> zrem k1 m1
31 (integer) 1
32 127.0.0.1:6379> zcard k1
33 (integer) 2
34 127.0.0.1:6379> zremrangebyscore k1 2 3
35 (integer) 1
36 127.0.0.1:6379> zremrangebyscore k1 2 10
37 (integer) 1
38 127.0.0.1:6379> zcard k1
39 (integer) 0

三、redis的相关命令 

keys pattern O(N) 获取所有匹配pattern参数的Keys。需要说明的是,在我们的正常操作中应该尽量避免对该命令的调用,因为对于大型数据库而言,该命令是非常耗时的。pattern支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。
del key [key ...] O(N) 从数据库删除中参数中指定的keys,如果指定键不存在,则直接忽略。
exists key O(1) 判断指定键是否存在。 1表示存在,0表示不存在。
move key db O(1) 将当前数据库中指定的键key移动到参数中指定的数据库中。若该key在目标数据库中已经存在,或者在当前数据库中不存在,该命令将不做任何操作并返回0。 移动成功返回1,否则0。
rename key newkey O(1) 为指定指定的键重新命名,如果两个keys的命令相同,或者是源key不存在,该命令都会返回相关的错误信息。如果newKey已经存在,则直接覆盖。
renamenx key newkey O(1) 如果新值不存在,则将参数中的原值修改为新值。其它条件和rename一致。1表示修改成功,否则0。
expire key seconds O(1) 该命令为指定的key设定超时的秒数,在超过该时间后,key被自动的删除。如果该Key在超时之前被修改,与该键关联的超时将被移除。1表示超时被设置,0则表示Key不存在,或不能被设置。
expireat key timestamp O(1) 该命令的逻辑功能和expire完全相同,差别是该命令指定的超时时间是绝对时间,而不是相对时间。该时间参数是Unix timestamp格式的,即从1970年1月1日开始所流经的秒数。1表示超时被设置,0则表示Key不存在,或不能被设置。
ttl key O(1) 获取该键所剩的超时描述。如果该键不存在或没有超时设置,则返回-1。
type key O(1) 获取与参数中指定键关联值的类型,该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash和zset,如果key不存在返回none。

 1 127.0.0.1:6379> keys *
 2 (empty list or set)
 3 127.0.0.1:6379> set str string
 4 OK
 5 127.0.0.1:6379> hset hash3 f1 v1
 6 (integer) 1
 7 127.0.0.1:6379> sadd set1 v1
 8 (integer) 1
 9 127.0.0.1:6379> zadd sortedset1 1 v1
10 (integer) 1
11 127.0.0.1:6379> lpush list1 v1 v2
12 (integer) 2
13 127.0.0.1:6379> keys *
14 1) 'hash3'
15 2) 'sortedset1'
16 3) 'list1'
17 4) 'str'
18 5) 'set1'
19 127.0.0.1:6379> keys s*
20 1) 'sortedset1'
21 2) 'str'
22 3) 'set1'
23 127.0.0.1:6379> exists list1
24 (integer) 1
25 127.0.0.1:6379> rename list1 list2
26 OK
27 127.0.0.1:6379> keys *
28 1) 'hash3'
29 2) 'sortedset1'
30 3) 'str'
31 4) 'list2'
32 5) 'set1'
33 127.0.0.1:6379> type list2
34 list
35 127.0.0.1:6379> type str
36 string
37 127.0.0.1:6379> set str2 v2
38 OK
39 127.0.0.1:6379> expire str2 10
40 (integer) 1
41 127.0.0.1:6379> ttl str2
42 (integer) 6
43 127.0.0.1:6379> ttl str2
44 (integer) -2
45 127.0.0.1:6379> keys *
46 1) 'hash3'
47 2) 'sortedset1'
48 3) 'str'
49 4) 'list2'
50 5) 'set1'
51 127.0.0.1:6379> move str 1
52 (integer) 1
53 127.0.0.1:6379> keys *
54 1) 'hash3'
55 2) 'sortedset1'
56 3) 'list2'
57 4) 'set1'
58 127.0.0.1:6379> select 1
59 OK
60 127.0.0.1:6379[1]> keys *
61 1) 'str'
62 127.0.0.1:6379[1]> select 0
63 OK
64 127.0.0.1:6379> del set1
65 (integer) 1
66 127.0.0.1:6379> keys *
67 1) 'hash3'
68 2) 'sortedset1'
69 3) 'list2'

四、redis的事务

1). 所有命令顺序执行,期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务不同的是,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为'BEGIN TRANSACTION'语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

multi 用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行exec时,这些命令才会被原子的执行。 始终返回OK
exec 执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了watch命令,那么只有当watch所监控的keys没有被修改的前提下,exec命令才能执行事务队列中的所有命令,否则exec将放弃当前事务中的所有命令。 原子性的返回事务中各条命令的返回结果。如果在事务中使用了watch,一旦事务被放弃,exec将返回NULL-multi-bulk回复。

 1 127.0.0.1:6379> multi
 2 OK
 3 127.0.0.1:6379> set k1 string
 4 QUEUED
 5 #由于k1为字符串类型,所以incr会报错,但是以后其他命令正常执行
 6 127.0.0.1:6379> incr k1
 7 QUEUED
 8 127.0.0.1:6379> set k1 newstring
 9 QUEUED
10 127.0.0.1:6379> get k1
11 QUEUED
12 127.0.0.1:6379> exec
13 1) OK
14 2) (error) ERR value is not an integer or out of range
15 3) OK
16 4) 'newstring'

discard 回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果watch命令被使用,该命令将unwatch所有的Keys。
watch key [key ...] O(1) 在multi命令执行之前,可以指定待监控的keys,然而在执行exec之前,如果被监控的keys发生修改,exec将放弃执行该事务队列中的所有命令。
unwatch O(1) 取消当前事务中指定监控的keys,如果执行了exec或discard命令,则无需手工执行该命令,因为事务中所有被监控的keys都将自动取消。 

 1 127.0.0.1:6379> set id 1
 2 OK
 3 127.0.0.1:6379> set name n1
 4 OK
 5 127.0.0.1:6379> set age 12
 6 OK
 7 127.0.0.1:6379> watch id
 8 OK
 9 127.0.0.1:6379> multi 
10 OK
11 127.0.0.1:6379> set name n2
12 QUEUED
13 127.0.0.1:6379> incr age
14 QUEUED
15 127.0.0.1:6379> exec
16 (nil)
17 127.0.0.1:6379> get age
18 '12'
19 127.0.0.1:6379> get name
20 'n1'

 注意,在提交事务之前,则执行exec命令之前,我们在另一个窗口对id进行修改(set id 2),可以看出,该事务没有执行成功

五、redis的主从复制

1). 同一个Master可以同步多个Slaves节点。

2). Slave同样可以接受其它Slaves的连接和同步请求。

3). Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。

4). Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。

5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。从而实现读写分离

在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。若Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。 

同时启动两个Redis服务器,可以考虑在同一台机器上启动两个Redis服务器,分别监听不同的端口,如6379和6380。复制redis.conf并命名为slave.conf,编辑该配置文件,在84行位置将其中监听的端口改为6380:配置如下port 6380,分配启动两个server,启动时可以将配置文件作为启动命令的参数。命令如下:redis-server redis.conf ,当我们把两个server都启动时,可以进行以下步骤:

1 redis-cli -p 6380

通过不同的端口来链接服务端,此时,当前客户端链接的6380端口的服务端,我们让这个服务端当做slave节点的角色。执行如下命令

slaveof 127.0.0.1 6379

当返回ok时,这里我Master-Slave建立成功。在监听端口为6379的服务器上我们用客户端进行操作

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6379
2 127.0.0.1:6379> set k1 v1
3 OK
4 127.0.0.1:6379> hset k2 f2 v2
5 (integer) 1
6 127.0.0.1:6379> 

在slave节点,获取该值:

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6380
2 127.0.0.1:6380> slaveof 127.0.0.1 6379
3 OK
4 127.0.0.1:6380> keys *
5 1) 'k1'
6 2) 'k2'
7 127.0.0.1:6380> get k1
8 'v1'

说明两个节点主从已经同步。实现了主从同步的效果。需要注意的是:上面的方式只是保证了在执行slaveof命令之后,redis_6380成为了redis_6379的slave,一旦服务(redis_6380)重新启动之后,他们之间的复制关系将终止。如果希望长期保证这两个服务器之间的Replication关系,可以在redis_6380的配置文件中做如下修改:

# slaveof <masterip> <masterport>改为slaveof 127.0.0.1 6379

保存退出。这样就可以保证Redis_6380服务程序在每次启动后都会主动建立与Redis_6379的Replication连接了。

六、redis的持久化

6.1、Redis提供的持久化机制: 

1). RDB持久化:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 

2). AOF持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

6.2、RDB机制的优势和劣势:

优势:
1). 采用该方式,整个Redis数据库将只包含一个文件,通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 性能最大化,对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,再由子进程完成这些持久化的工作,这样可以极避免服务进程执行IO操作。
劣势:

1). 如果你想保证数据的高可用性,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务一定的时间。

6.3、AOF机制的优势和劣势: 

优势
1). 带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。

2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,在Redis下一次启动之前,可以通过redis-check-aof工具来解决数据一致性的问题。

3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。

4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
劣势
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。

介绍完理论之后,我们配置redis的持久化方案:

rdb方案,在redis.conf中如下配置(默认配置) 

1 save 900 1              #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
2 save 300 10            #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
3 save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

aof方案的配置:

1 在Redis的配置文件中存在三种同步方式,它们分别是:
2 appendfsync always     #每次有数据修改发生时都会写入AOF文件。
3 appendfsync everysec  #每秒钟同步一次,该策略为AOF的缺省策略。
4 appendfsync no          #从不同步。高效但是数据不会被持久化。

七、redis的分片

分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,Redis 引入另一种哈希槽(hash slot)的概念。Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法得出结果,然后对 16384 求余数,这样每个 key 对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同节点。

原来的redis分片实现:

客户端分片(Client side partitioning),客户端直接选择正确的节点来写入和读取指定键。

代理协助分片(Proxy assisted partitioning),客户端发送请求到一个可以理解 Redis 协议的代理上,而不是直接发送请求到 Redis 实例上。代理会根据配置好的分片模式,来保证转发请求到正确的 Redis 实例,并返回响应给客户端。

查询路由(Query routing),发送查询到一个随机实例,这个实例会保证转发查询到正确的节点。 

新版本Redis的解决办法:

Redis3.0版的一大特性就是支持集群(Cluster)功能。Redis集群是自动分片和高可用的首选方式。集群的特点在于拥有和单机实例同样的功能,同时在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持。

搭建redis集群环境需要执行的ruby的脚本,所以需要安装ruby的环境。建议用yum进行安装,由于具体的操作环境不相同,所以具体操作过程还需视操作环境而定 

1 [root@root java]# yum install ruby
2 [root@root java]# yum install rubygems
3 [root@root java]# gem install redis

期间会出现选择选项,键入yes即可。当出现Successfully installed redis-3.3.1  1 gem installed,说明redis集群需要的ruby环境安装成功。开始搭建redis环境

创建redis-cluster文件夹,并在其中创建6379,6380,6381文件夹,修改redis.conf文件,并将其中的端口分别设置成6379,6380,6381,redis.conf中的其他配置为

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

结构目录如下:

 1 [root@storm1 java]# cd redis-cluster/
 2 [root@storm1 redis-cluster]# ll
 3 total 12
 4 drwxr-xr-x. 2 root root 4096 Nov 14 05:50 6379
 5 drwxr-xr-x. 2 root root 4096 Nov 14 05:51 6380
 6 drwxr-xr-x. 2 root root 4096 Nov 14 05:52 6381
 7 [root@storm1 redis-cluster]# cd 6379
 8 [root@storm1 6379]# cat redis.conf 
 9 port 6379
10 daemonize yes
11 cluster-enabled yes
12 cluster-config-file nodes.conf
13 cluster-node-timeout 5000
14 appendonly yes[root@storm1 6379]# more ../6380/redis.conf 
15 port 6380
16 daemonize yes
17 cluster-enabled yes
18 cluster-config-file nodes.conf
19 cluster-node-timeout 5000
20 appendonly yes
21 [root@storm1 6379]# 

分别启动这3个redis实例,并创建集群,让三个实例互相通讯:

 1 [root@storm1 redis-3.2.5]# src/redis-trib.rb create --replicas 0 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381
 2 >>> Creating cluster
 3 >>> Performing hash slots allocation on 3 nodes...
 4 Using 3 masters:
 5 127.0.0.1:6379
 6 127.0.0.1:6380
 7 127.0.0.1:6381
 8 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379
 9    slots:0-5460 (5461 slots) master
10 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380
11    slots:5461-10922 (5462 slots) master
12 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381
13    slots:10923-16383 (5461 slots) master
14 Can I set the above configuration? (type 'yes' to accept): yes
15 >>> Nodes configuration updated
16 >>> Assign a different config epoch to each node
17 >>> Sending CLUSTER MEET messages to join the cluster
18 Waiting for the cluster to join....
19 >>> Performing Cluster Check (using node 127.0.0.1:6379)
20 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379
21    slots:0-5460 (5461 slots) master
22    0 additional replica(s)
23 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381
24    slots:10923-16383 (5461 slots) master
25    0 additional replica(s)
26 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380
27    slots:5461-10922 (5462 slots) master
28    0 additional replica(s)
29 [OK] All nodes agree about slots configuration.
30 >>> Check for open slots...
31 >>> Check slots coverage...
32 [OK] All 16384 slots covered.

至此redis集群即搭建成功,简单进行测试一下

1 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6379
2 127.0.0.1:6379> set k1 v1
3 -> Redirected to slot [12706] located at 127.0.0.1:6381
4 OK
5 127.0.0.1:6381> exit
6 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6381
7 127.0.0.1:6381> keys *
8 1) 'k1'
9 127.0.0.1:6381> 

可以看到,虽然我们第一次连接的是6379端口,redis cluster 自动帮我们重定向到 6381 。在6381端口的实例中出现了我们之前设置的k1,说明整个集群是工作的。

八、redis的管理命令

config get parameter 用于读取服务器的运行时参数,但是并不是所有的配置参数都可以通过该命令进行读取。该命令的参数接受glob风格的模式匹配规则,因此如果参数中包含模式元字符,那么所有匹配的参数都将以key/value方式被列出。如果参数是*,那么该命令支持的所有参数都将被列出。

config set parameter value 该命令用于配置Redis服务器的运行时参数,在设置成功之后无需重启便可生效。然而并非所有的参数都可以通过该命令进行动态设置。
dbsize 返回当前打开的数据库中keys的数量。
flushall  清空当前服务器管理的数据库中的所有keys,不仅限于当前打开的数据库。
flushdb  清空当前数据库中的所有keys。
info  获取和服务器运行状况相关的一些列统计数字。
save 设置RDB持久化模式的保存策略。
shutdown  停止所有的客户端,同时以阻塞的方式执行内存数据持久化。如果AOF模式被启用,则将缓存中的数据flush到AOF文件。退出服务器。
slaveof host port 该命令用于修改slave服务器的主从复制设置。
slowlog subcommand [argument] 该命令主要用于读取执行时间较长的命令。由于slowlog队列不会被持久化到磁盘,因此Redis在收集命令时不会对性能产生很大的影响。通常我们可以将参数'slowlog-log-slower-than'设置为0,以便收集所有命令的执行时间。该命令还包含以下几个子命令:
1). slowlog get N: 从slowlog队列中读取命令信息,N表示最近N条命令的信息。
2). slowlog len:获取slowlog队列的长度。
3). slowlog reset:清空slowlog中的内容。

 1 redis 127.0.0.1:6379> config get port
 2 1) 'port'
 3 2) '6379'
 4 redis 127.0.0.1:6379> keys *
 5 1) 'k1'
 6 redis 127.0.0.1:6379> flushdb
 7 OK
 8 redis 127.0.0.1:6379> keys *
 9 (empty list or set)
10 redis 127.0.0.1:6379> dbsize
11 (integer) 0
12 redis 127.0.0.1:6379> set k1 v1
13 OK
14 redis 127.0.0.1:6379> dbsize
15 (integer) 1

九、redis的java操作

maven依赖 

1 <dependency>
2     <groupId>redis.clients</groupId>
3     <artifactId>jedis</artifactId>
4     <version>2.6.2</version>
5     <type>jar</type>
6     <scope>compile</scope>
7 </dependency>

 java代码:

 1 import redis.clients.jedis.Jedis;
 2 
 3 public class RedisDao {
 4 
 5     public static void main(String[] args) {
 6         Jedis jedis = new Jedis('127.0.0.1', 6379);
 7         jedis.set('k2', 'v2');
 8         System.out.println(jedis.get('k2'));
 9         jedis.hset('k3', 'f1', 'v1');
10         System.out.println(jedis.hget('k3', 'f1'));
11         System.out.println(jedis.keys('*'));
12         jedis.close();
13     }
14 }

十、redis与spring整合 

10.1 引入jedis包和spring包

10.2 spring-mvc.xml 

 1 <?xml version='1.0' encoding='UTF-8'?>
 2 <beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 3     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd' default-autowire='byName'>
 4 
 5     <bean id='redisClient' class='com.eztcn.commons.redis.RedisClientFactoryBean'>
 6         <!-- 单个应用中的链接池最大链接数,默认8 -->
 7         <property name='maxTotal' value='150' />
 8         <!-- 单个应用中的链接池最大空闲数,默认8 -->
 9         <property name='maxIdle' value='50' />
10         <!-- 单个应用中的链接池最大链接数,默认8 -->
11         <property name='minIdle' value='30' />
12         <!-- 设置在每一次取对象时测试ping -->
13         <property name='testOnBorrow' value='false' />
14         <!-- host:port -->
15           <property name='ipConfString' value='192.168.1.60:7001' /> 
16     </bean>
17 </beans>

 当然需要在spring配置文件中引入该配置文件:<import resource='spring/spring-config-redis.xml' />

10.3 RedisClientFactoryBean.java 

 1 package com.commons.redis;
 2 
 3 import org.apache.commons.lang3.StringUtils;
 4 import org.springframework.beans.factory.FactoryBean;
 5 
 6 public class RedisClientFactoryBean implements FactoryBean<RedisClient> {
 7     private RedisClientConfig redisClientConfig = new RedisClientConfig();
 8 
 9     public RedisClient getObject() throws Exception {
10         if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) {
11             return new RedisClient(this.redisClientConfig);
12         }
13         throw new RedisInitializerException('RedisClient init parameter masterConfString is empty,please check spring config file!');
14     }
15 
16     public Class<?> getObjectType() {
17         return RedisClient.class;
18     }
19 
20     public boolean isSingleton() {
21         return true;
22     }
23 
24     public void setIpConfString(String string) {
25         this.redisClientConfig.setIpConfString(string);
26     }
27 
28     public void setMaxTotal(int maxTotal) {
29         this.redisClientConfig.setMaxTotal(maxTotal);
30     }
31 
32     public void setMaxIdle(int maxIdle) {
33         this.redisClientConfig.setMaxIdle(maxIdle);
34     }
35 
36     public void setMinIdle(int minIdle) {
37         this.redisClientConfig.setMinIdle(minIdle);
38     }
39 
40     public void setTestOnBorrow(boolean flag) {
41         this.redisClientConfig.setTestOnBorrow(flag);
42     }
43 }

10.4 RedisClientConfig.java

 1 package com.commons.redis;
 2 
 3 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 4 
 5 /**
 6  * 
 7  * @描述 : 配置redis的相关属性
 8  * @创建时间: 2015年7月20日上午11:05:53
 9  *
10  */
11 public class RedisClientConfig {
12     private GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
13     
14     private String ipConfString;
15 
16     /**
17      * 
18      * @描述 : 单个应用中的链接池最大链接数
19      * @创建时间: 2015年7月20日上午11:11:10
20      *
21      * @param maxTotal
22      */
23     public void setMaxTotal(int maxTotal) {
24         this.jedisPoolConfig.setMaxTotal(maxTotal);
25     }
26 
27     /**
28      * @描述 :单个应用中的链接池最大空闲数 
29      * @创建时间: 2015年7月20日上午11:11:28
30      *
31      * @param maxIdle
32      */
33     
34     
35     public void setMaxIdle(int maxIdle) {
36         this.jedisPoolConfig.setMaxIdle(maxIdle);
37     }
38 
39     
40     /**
41      * @描述 : 单个应用中的链接池最大链接数
42      * @创建时间: 2015年7月20日上午11:11:43
43      *
44      * @param maxIdle
45      */
46     public void setMinIdle(int minIdle) {
47         this.jedisPoolConfig.setMinIdle(minIdle);
48     }
49 
50     /**
51      * @描述 : 设置在每一次取对象时测试ping 
52      * @创建时间: 2015年7月20日上午11:11:58
53      *
54      * @param flag
55      */
56     public void setTestOnBorrow(boolean flag) {
57         this.jedisPoolConfig.setTestOnBorrow(flag);
58     }
59 
60     public GenericObjectPoolConfig getJedisPoolConfig() {
61         return this.jedisPoolConfig;
62     }
63 
64     public String getIpConfString() {
65         return this.ipConfString;
66     }
67 
68     public void setIpConfString(String ipConfString) {
69         this.ipConfString = ipConfString;
70     }
71 }

10.5 RedisClient.java

  1 package com.commons.redis;
  2 
  3 import java.util.List;
  4 import java.util.Map;
  5 import java.util.Set;
  6 
  7 import org.apache.commons.lang3.StringUtils;
  8 import org.apache.commons.logging.Log;
  9 import org.apache.commons.logging.LogFactory;
 10 
 11 import redis.clients.jedis.BinaryClient;
 12 import redis.clients.jedis.Jedis;
 13 import redis.clients.jedis.JedisPool;
 14 
 15 public class RedisClient {
 16     private static final Log LOG = LogFactory.getLog(RedisClient.class);
 17     private RedisClientConfig redisClientConfig;
 18     private JedisPool jedisPool;
 19 
 20     public RedisClient(RedisClientConfig redisClientConfig) {
 21         this.redisClientConfig = redisClientConfig;
 22         init();
 23     }
 24 
 25     /**
 26      * 
 27      * @描述 : 初始化,配置ip和端口
 28      * @创建时间: 2015年7月20日下午1:43:29
 29      *
 30      */
 31     private void init() {
 32         LOG.info('redis client init start~');
 33         String ip = '';
 34         int port;
 35         if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) {
 36             String[] ipPortArray = this.redisClientConfig.getIpConfString().split(':');
 37             if (ipPortArray.length == 1) {
 38                 throw new RedisInitializerException(ipPortArray + ' is not include host:port or host:port after split ':'');
 39             }
 40             ip = ipPortArray[0];
 41             port = Integer.valueOf(ipPortArray[1]).intValue();
 42         } else {
 43             throw new RuntimeException('init throw exception');
 44         }
 45         LOG.info('write redis client connect ip:' + ip + ',port:' + port);
 46         this.jedisPool = new JedisPool(this.redisClientConfig.getJedisPoolConfig(), ip, port);
 47     }
 48 
 49     /**
 50      * 
 51      * @描述 : 设置键值对
 52      * @创建时间: 2015年7月20日下午1:44:10
 53      *
 54      * @param key
 55      * @param value
 56      * @return
 57      * @throws RedisAccessException
 58      */
 59     public String set(String key, String value) throws RedisAccessException {
 60         Jedis client = null;
 61         try {
 62             client = jedisPool.getResource();
 63             return client.set(key, value);
 64         } catch (Exception e) {
 65             LOG.error(e.getMessage(), e);
 66             throw new RedisAccessException(e);
 67         } finally {
 68             if (null != client) {
 69                 jedisPool.returnResourceObject(client);
 70             }
 71         }
 72     }
 73 
 74     /**
 75      * 
 76      * @描述 : 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX
 77      *     命令将覆写旧值。
 78      * @创建时间: 2015年7月20日下午1:44:36
 79      *
 80      * @param key
 81      * @param seconds
 82      * @param value
 83      * @return
 84      * @throws RedisAccessException
 85      */
 86     public String set(String key, int seconds, String value) throws RedisAccessException {
 87         Jedis client = null;
 88         try {
 89             client = jedisPool.getResource();
 90             return client.setex(key, seconds, value);
 91         } catch (Exception e) {
 92             LOG.error(e.getMessage(), e);
 93             throw new RedisAccessException(e);
 94         } finally {
 95             if (null != client) {
 96                 jedisPool.returnResourceObject(client);
 97             }
 98         }
 99     }
100 
101     /**
102      * 
103      * @描述 : 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 如果 key 不存在,
104      *     APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
105      * @创建时间: 2015年7月20日下午1:45:55
106      *
107      * @param key
108      * @param value
109      * @return
110      * @throws RedisAccessException
111      */
112     public Long append(String key, String value) throws RedisAccessException {
113         Jedis client = null;
114         try {
115             client = jedisPool.getResource();
116             return client.append(key, value);
117         } catch (Exception e) {
118             LOG.error(e.getMessage(), e);
119             throw new RedisAccessException(e);
120         } finally {
121             if (null != client) {
122                 jedisPool.returnResourceObject(client);
123             }
124         }
125     }
126 
127     /**
128      * 
129      * @描述 : 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 null 。 假如 key
130      *     储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。
131      * @创建时间: 2015年7月20日下午1:47:10
132      *
133      * @param key
134      * @return
135      * @throws RedisAccessException
136      */
137     public String get(String key) throws RedisAccessException {
138         Jedis client = null;
139         try {
140             client = jedisPool.getResource();
141             return client.get(key);
142         } catch (Exception e) {
143             LOG.error(e.getMessage(), e);
144             throw new RedisAccessException(e);
145         } finally {
146             if (null != client) {
147                 jedisPool.returnResourceObject(client);
148             }
149         }
150     }
151 
152     /**
153      * 
154      * @描述 : 删除给定的一个或多个 key 。 不存在的 key 会被忽略。
155      * @创建时间: 2015年7月20日下午1:48:37
156      *
157      * @param key
158      * @return
159      * @throws RedisAccessException
160      */
161     public Long del(String key) throws RedisAccessException {
162         Jedis client = null;
163         try {
164             client = jedisPool.getResource();
165             return client.del(key);
166         } catch (Exception e) {
167             LOG.error(e.getMessage(), e);
168             throw new RedisAccessException(e);
169         } finally {
170             if (null != client) {
171                 jedisPool.returnResourceObject(client);
172             }
173         }
174     }
175 
176     /**
177      * 
178      * @描述 : 检查给定 key 是否存在。
179      * @创建时间: 2015年7月20日下午1:48:48
180      *
181      * @param key
182      * @return
183      * @throws RedisAccessException
184      */
185     public Boolean exists(String key) throws RedisAccessException {
186         Jedis client = null;
187         try {
188             client = jedisPool.getResource();
189             return client.exists(key);
190         } catch (Exception e) {
191             LOG.error(e.getMessage(), e);
192             throw new RedisAccessException(e);
193         } finally {
194             if (null != client) {
195                 jedisPool.returnResourceObject(client);
196             }
197         }
198     }
199 
200     /**
201      * @描述 : 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
202      * @创建时间: 2015年7月20日下午1:49:29
203      *
204      * @param key
205      * @param seconds
206      * @return
207      * @throws RedisAccessException
208      */
209     public Long expire(String key, int seconds) throws RedisAccessException {
210         Jedis client = null;
211         try {
212             client = jedisPool.getResource();
213             return client.expire(key, seconds);
214         } catch (Exception e) {
215             LOG.error(e.getMessage(), e);
216             throw new RedisAccessException(e);
217         } finally {
218             if (null != client) {
219                 jedisPool.returnResourceObject(client);
220             }
221         }
222     }
223     
224     
225     
226     /**
227      * @描述 : 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
228      * @创建时间: 2015年7月20日下午1:49:29
229      *
230      * @param key
231      * @param seconds
232      * @return
233      * @throws RedisAccessException
234      */
235     public Long expireAt(String key, long unixTime) throws RedisAccessException {
236         Jedis client = null;
237         try {
238             client = jedisPool.getResource();
239             return client.expireAt(key,unixTime);
240         } catch (Exception e) {
241             LOG.error(e.getMessage(), e);
242             throw new RedisAccessException(e);
243         } finally {
244             if (null != client) {
245                 jedisPool.returnResourceObject(client);
246             }
247         }
248     }
249 
250     /**
251      * 
252      * @描述 : 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key
253      *     存在但不是字符串类型时,返回一个错误。
254      * @创建时间: 2015年7月20日下午1:50:28
255      *
256      * @param key
257      * @param value
258      * @return
259      * @throws RedisAccessException
260      */
261     public String getSet(String key, String value) throws RedisAccessException {
262         Jedis client = null;
263         try {
264             client = jedisPool.getResource();
265             return client.getSet(key, value);
266         } catch (Exception e) {
267             LOG.error(e.getMessage(), e);
268             throw new RedisAccessException(e);
269         } finally {
270             if (null != client) {
271                 jedisPool.returnResourceObject(client);
272             }
273         }
274     }
275 
276     /**
277      * 
278      * @描述 : 将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。
279      * @创建时间: 2015年7月20日下午1:52:07
280      *
281      * @param key
282      * @param value
283      * @return
284      * @throws RedisAccessException
285      */
286     public Long setnx(String key, String value) throws RedisAccessException {
287         Jedis client = null;
288         try {
289             client = jedisPool.getResource();
290             return client.setnx(key, value);
291         } catch (Exception e) {
292             LOG.error(e.getMessage(), e);
293             throw new RedisAccessException(e);
294         } finally {
295             if (null != client) {
296                 jedisPool.returnResourceObject(client);
297             }
298         }
299     }
300 
301     /**
302      * 
303      * @描述 : 将哈希表 key 中的域 field 的值设为 value 。 如果 key 不存在,一个新的哈希表被创建并进行 HSET操作。
304      *     如果域 field 已经存在于哈希表中,旧值将被覆盖。
305      * @创建时间: 2015年7月20日下午1:53:23
306      *
307      * @param key
308      * @param field
309      * @param value
310      * @return
311      * @throws RedisAccessException
312      */
313     public Long hset(String key, String field, String value) throws RedisAccessException {
314         Jedis client = null;
315         try {
316             client = jedisPool.getResource();
317             return client.hset(key, field, value);
318         } catch (Exception e) {
319             LOG.error(e.getMessage(), e);
320             throw new RedisAccessException(e);
321         } finally {
322             if (null != client) {
323                 jedisPool.returnResourceObject(client);
324             }
325         }
326     }
327 
328     /**
329      * 
330      * @描述 :返回哈希表 key 中给定域 field 的值。
331      * @创建时间: 2015年7月20日下午1:54:24
332      *
333      * @param key
334      * @param field
335      * @return
336      * @throws RedisAccessException
337      */
338     public String hget(String key, String field) throws RedisAccessException {
339         Jedis client = null;
340         try {
341             client = jedisPool.getResource();
342             return client.hget(key, field);
343         } catch (Exception e) {
344             LOG.error(e.getMessage(), e);
345             throw new RedisAccessException(e);
346         } finally {
347             if (null != client) {
348                 jedisPool.returnResourceObject(client);
349             }
350         }
351     }
352 
353     /**
354      * 
355      * @描述 : 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。若域 field
356      *     已经存在,该操作无效。 如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。
357      * @创建时间: 2015年7月20日下午1:54:44
358      *
359      * @param key
360      * @param field
361      * @param value
362      * @return
363      * @throws RedisAccessException
364      */
365     public Long hsetnx(String key, String field, String value) throws RedisAccessException {
366         Jedis client = null;
367         try {
368             client = jedisPool.getResource();
369             return client.hsetnx(key, field, value);
370         } catch (Exception e) {
371             LOG.error(e.getMessage(), e);
372             throw new RedisAccessException(e);
373         } finally {
374             if (null != client) {
375                 jedisPool.returnResourceObject(client);
376             }
377         }
378     }
379 
380     /**
381      * 
382      * @描述 :同时将多个 field-value (域-值)对设置到哈希表 key 中。此命令会覆盖哈希表中已存在的域。 如果 key
383      *     不存在,一个空哈希表被创建并执行 HMSET 操作。
384      * @创建时间: 2015年7月20日下午1:58:26
385      *
386      * @param key
387      * @param hash
388      * @return
389      * @throws RedisAccessException
390      */
391     public String hmset(String key, Map<String, String> hash) throws RedisAccessException {
392         Jedis client = null;
393         try {
394             client = jedisPool.getResource();
395             return client.hmset(key, hash);
396         } catch (Exception e) {
397             LOG.error(e.getMessage(), e);
398             throw new RedisAccessException(e);
399         } finally {
400             if (null != client) {
401                 jedisPool.returnResourceObject(client);
402             }
403         }
404     }
405 
406     /**
407      * 
408      * @描述 : 返回哈希表 key 中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个 null 值。 因为不存在的 key
409      *     被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 null 值的表。
410      * @创建时间: 2015年7月20日下午1:57:32
411      *
412      * @param key
413      * @param fields
414      * @return
415      * @throws RedisAccessException
416      */
417     public List<String> hmget(String key, String[] fields) throws RedisAccessException {
418         Jedis client = null;
419         try {
420             client = jedisPool.getResource();
421             return client.hmget(key, fields);
422         } catch (Exception e) {
423             LOG.error(e.getMessage(), e);
424             throw new RedisAccessException(e);
425         } finally {
426             if (null != client) {
427                 jedisPool.returnResourceObject(client);
428             }
429         }
430     }
431 
432     /**
433      * 
434      * @描述 :删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
435      * @创建时间: 2015年7月20日下午1:59:32
436      *
437      * @param key
438      * @param fields
439      * @return
440      * @throws RedisAccessException
441      */
442     public Long hdel(String key, String[] fields) throws RedisAccessException {
443         Jedis client = null;
444         try {
445             client = jedisPool.getResource();
446             return client.hdel(key, fields);
447         } catch (Exception e) {
448             LOG.error(e.getMessage(), e);
449             throw new RedisAccessException(e);
450         } finally {
451             if (null != client) {
452                 jedisPool.returnResourceObject(client);
453             }
454         }
455     }
456 
457     /**
458      * 
459      * @描述 : 返回哈希表 key 中域的数量。
460      * @创建时间: 2015年7月20日下午2:00:13
461      *
462      * @param key
463      * @return
464      * @throws RedisAccessException
465      */
466     public Long hlen(String key) throws RedisAccessException {
467         Jedis client = null;
468         try {
469             client = jedisPool.getResource();
470             return client.hlen(key);
471         } catch (Exception e) {
472             LOG.error(e.getMessage(), e);
473             throw new RedisAccessException(e);
474         } finally {
475             if (null != client) {
476                 jedisPool.returnResourceObject(client);
477             }
478         }
479     }
480 
481     /**
482      * 
483      * @描述 :返回哈希表 key 中的所有域。
484      * @创建时间: 2015年7月20日下午2:00:59
485      *
486      * @param key
487      * @return
488      * @throws RedisAccessException
489      */
490     public Set<String> hkeys(String key) throws RedisAccessException {
491         Jedis client = null;
492         try {
493             client = jedisPool.getResource();
494             return client.hkeys(key);
495         } catch (Exception e) {
496             LOG.error(e.getMessage(), e);
497             throw new RedisAccessException(e);
498         } finally {
499             if (null != client) {
500                 jedisPool.returnResourceObject(client);
501             }
502         }
503     }
504 
505     /**
506      * 
507      * @描述 : 返回哈希表 key 中所有域的值。
508      * @创建时间: 2015年7月20日下午2:01:06
509      *
510      * @param key
511      * @return
512      * @throws RedisAccessException
513      */
514     public List<String> hvals(String key) throws RedisAccessException {
515         Jedis client = null;
516         try {
517             client = jedisPool.getResource();
518             return client.hvals(key);
519         } catch (Exception e) {
520             LOG.error(e.getMessage(), e);
521             throw new RedisAccessException(e);
522         } finally {
523             if (null != client) {
524                 jedisPool.returnResourceObject(client);
525             }
526         }
527     }
528 
529     /**
530      * 
531      * @描述 : 返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field
532      *     name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
533      * @创建时间: 2015年7月20日下午2:01:36
534      *
535      * @param key
536      * @return
537      * @throws RedisAccessException
538      */
539     public Map<String, String> hgetAll(String key) throws RedisAccessException {
540         Jedis client = null;
541         try {
542             client = jedisPool.getResource();
543             return client.hgetAll(key);
544         } catch (Exception e) {
545             LOG.error(e.getMessage(), e);
546             throw new RedisAccessException(e);
547         } finally {
548             if (null != client) {
549                 jedisPool.returnResourceObject(client);
550             }
551         }
552     }
553 
554     /**
555      * 
556      * @描述 :查看哈希表 key 中,给定域 field 是否存在。
557      * @创建时间: 2015年7月20日下午2:02:38
558      *
559      * @param key
560      * @param field
561      * @return
562      * @throws RedisAccessException
563      */
564     public Boolean hexists(String key, String field) throws RedisAccessException {
565         Jedis client = null;
566         try {
567             client = jedisPool.getResource();
568             return client.hexists(key, field);
569         } catch (Exception e) {
570             LOG.error(e.getMessage(), e);
571             throw new RedisAccessException(e);
572         } finally {
573             if (null != client) {
574                 jedisPool.returnResourceObject(client);
575             }
576         }
577     }
578 
579     /**
580      * 
581      * @描述 : 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
582      * @创建时间: 2015年7月20日下午2:02:44
583      *
584      * @param key
585      * @param values
586      * @return
587      * @throws RedisAccessException
588      */
589     public Long rpush(String key, String[] values) throws RedisAccessException {
590         Jedis client = null;
591         try {
592             client = jedisPool.getResource();
593             return client.rpush(key, values);
594         } catch (Exception e) {
595             LOG.error(e.getMessage(), e);
596             throw new RedisAccessException(e);
597         } finally {
598             if (null != client) {
599                 jedisPool.returnResourceObject(client);
600             }
601         }
602     }
603 
604     /**
605      * 
606      * @描述 : 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
607      * @创建时间: 2015年7月20日下午2:03:20
608      *
609      * @param key
610      * @param value
611      * @return
612      * @throws RedisAccessException
613      */
614     public Long rpushx(String key, String value) throws RedisAccessException {
615         Jedis client = null;
616         try {
617             client = jedisPool.getResource();
618             return client.rpushx(key, new String[] { value });
619         } catch (Exception e) {
620             LOG.error(e.getMessage(), e);
621             throw new RedisAccessException(e);
622         } finally {
623             if (null != client) {
624                 jedisPool.returnResourceObject(client);
625             }
626         }
627     }
628 
629     /**
630      * 
631      * @描述 : 将一个或多个值 value 插入到列表 key 的表头
632      * @创建时间: 2015年7月20日下午2:04:13
633      *
634      * @param key
635      * @param values
636      * @return
637      * @throws RedisAccessException
638      */
639     public Long lpush(String key, String[] values) throws RedisAccessException {
640         Jedis client = null;
641         try {
642             client = jedisPool.getResource();
643             return client.lpush(key, values);
644         } catch (Exception e) {
645             LOG.error(e.getMessage(), e);
646             throw new RedisAccessException(e);
647         } finally {
648             if (null != client) {
649                 jedisPool.returnResourceObject(client);
650             }
651         }
652     }
653 
654     /**
655      * 
656      * @描述 : 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。 和 LPUSH 命令相反,当 key 不存在时,
657      *     LPUSHX 命令什么也不做。
658      * @创建时间: 2015年7月20日下午2:05:09
659      *
660      * @param key
661      * @param value
662      * @return
663      * @throws RedisAccessException
664      */
665     public Long lpushx(String key, String value) throws RedisAccessException {
666         Jedis client = null;
667         try {
668             client = jedisPool.getResource();
669             return client.lpushx(key, new String[] { value });
670         } catch (Exception e) {
671             LOG.error(e.getMessage(), e);
672             throw new RedisAccessException(e);
673         } finally {
674             if (null != client) {
675                 jedisPool.returnResourceObject(client);
676             }
677         }
678     }
679 
680     /**
681      * 
682      * @描述 : 返回列表 key 的长度。如果 key 不存在,则 key 被解释为一个空列表,返回 0 . 如果 key
683      *     不是列表类型,返回一个错误。
684      * @创建时间: 2015年7月20日下午2:05:25
685      *
686      * @param key
687      * @return
688      * @throws RedisAccessException
689      */
690     public Long llen(String key) throws RedisAccessException {
691         Jedis client = null;
692         try {
693             client = jedisPool.getResource();
694             return client.llen(key);
695         } catch (Exception e) {
696             LOG.error(e.getMessage(), e);
697             throw new RedisAccessException(e);
698         } finally {
699             if (null != client) {
700                 jedisPool.returnResourceObject(client);
701             }
702         }
703     }
704 
705     /**
706      * 
707      * @描述 : 返回列表 key 中,下标为 index 的元素。
708      * @创建时间: 2015年7月20日下午2:05:37
709      *
710      * @param key
711      * @param index
712      * @return
713      * @throws RedisAccessException
714      */
715     public String lindex(String key, long index) throws RedisAccessException {
716         Jedis client = null;
717         try {
718             client = jedisPool.getResource();
719             return client.lindex(key, index);
720         } catch (Exception e) {
721             LOG.error(e.getMessage(), e);
722             throw new RedisAccessException(e);
723         } finally {
724             if (null != client) {
725                 jedisPool.returnResourceObject(client);
726             }
727         }
728     }
729 
730     /**
731      * 
732      * @描述 : 将列表 key 下标为 index 的元素的值设置为 value 。当 index 参数超出范围,或对一个空列表( key
733      *     不存在)进行 LSET 时,返回一个错误。
734      * @创建时间: 2015年7月20日下午2:07:06
735      *
736      * @param key
737      * @param index
738      * @param value
739      * @return
740      * @throws RedisAccessException
741      */
742     public String lset(String key, long index, String value) throws RedisAccessException {
743         Jedis client = null;
744         try {
745             client = jedisPool.getResource();
746             return client.lset(key, index, value);
747         } catch (Exception e) {
748             LOG.error(e.getMessage(), e);
749             throw new RedisAccessException(e);
750         } finally {
751             if (null != client) {
752                 jedisPool.returnResourceObject(client);
753             }
754         }
755     }
756 
757     /**
758      * 
759      * @描述 : 移除并返回列表 key 的头元素。
760      * @创建时间: 2015年7月20日下午2:07:10
761      *
762      * @param key
763      * @return
764      * @throws RedisAccessException
765      */
766     public String lpop(String key) throws RedisAccessException {
767         Jedis client = null;
768         try {
769             client = jedisPool.getResource();
770             return client.lpop(key);
771         } catch (Exception e) {
772             LOG.error(e.getMessage(), e);
773             throw new RedisAccessException(e);
774         } finally {
775             if (null != client) {
776                 jedisPool.returnResourceObject(client);
777             }
778         }
779     }
780 
781     /**
782      * 
783      * @描述 : 移除并返回列表 key 的尾元素。
784      * @创建时间: 2015年7月20日下午2:07:13
785      *
786      * @param key
787      * @return
788      * @throws RedisAccessException
789      */
790     public String rpop(String key) throws RedisAccessException {
791         Jedis client = null;
792         try {
793             client = jedisPool.getResource();
794             return client.rpop(key);
795         } catch (Exception e) {
796             LOG.error(e.getMessage(), e);
797             throw new RedisAccessException(e);
798         } finally {
799             if (null != client) {
800                 jedisPool.returnResourceObject(client);
801             }
802         }
803     }
804 
805     /**
806      * 
807      * @描述 : 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。当 pivot 不存在于列表 key 时,不执行任何操作。
808      *     key 不存在时, key 被视为空列表,不执行任何操作。 如果 key 不是列表类型,返回一个错误。
809      * @创建时间: 2015年7月20日下午2:07:37
810      *
811      * @param key
812      * @param where
813      * @param pivot
814      * @param value
815      * @return
816      * @throws RedisAccessException
817      */
818     public Long linsert(String key, BinaryClient.LIST_POSITION where, String pivot, String value) throws RedisAccessException {
819         Jedis client = null;
820         try {
821             client = jedisPool.getResource();
822             return client.linsert(key, where, pivot, value);
823         } catch (Exception e) {
824             LOG.error(e.getMessage(), e);
825             throw new RedisAccessException(e);
826         } finally {
827             if (null != client) {
828                 jedisPool.returnResourceObject(client);
829             }
830         }
831     }
832     
833     /**
834      * @描述 : 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
835      * @创建时间: 2014-6-16下午2:31:58
836      * 
837      * @param key
838      * @return
839      * @throws RedisAccessException
840      */
841     public Long incr(String key) throws RedisAccessException {
842         Jedis client = null;
843         try {
844             client = jedisPool.getResource();
845             return client.incr(key);
846         } catch (Exception e) {
847             LOG.error(e.getMessage(), e);
848             throw new RedisAccessException(e);
849         } finally {
850             if (null != client) {
851                 jedisPool.returnResourceObject(client);
852             }
853         }
854     }
855     
856     
857     /**
858      * @描述 :  将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行  INCRBY 命令。
859      * @创建时间: 2014-6-16下午2:31:58
860      * 
861      * @param key
862      * @return
863      * @throws RedisAccessException
864      */
865     public double incrBy(String key,long value) throws RedisAccessException {
866         Jedis client = null;
867         try {
868             client = jedisPool.getResource();
869             return client.incrBy(key, value);
870         } catch (Exception e) {
871             LOG.error(e.getMessage(), e);
872             throw new RedisAccessException(e);
873         } finally {
874             if (null != client) {
875                 jedisPool.returnResourceObject(client);
876             }
877         }
878     }
879 
880 }

OK,这个关于redis的相关内容更新完毕! 

本文地址: http://www.cnblogs.com/gzy-blog/p/6058849.html

Tag标签: 主从   集群  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规