本文是阅读《Redis入门指南》时的一些笔记摘抄,用于自学。
一、常用命令:
1. 获得符合规则的键名列表
集合类型(set)键可以存储至多232-1个字符串。
“发布/订阅”模式
发布者发布消息的命令是PUBLISH,用法是PUBLISH channel message,如向channel.1说一
声“hi”:
redis>PUBLISH channel.1 hi
(integer) 0
订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel[channel …]。
例如:
redis A>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.1"
3) (integer) 1
除了可以使用SUBSCRIBE命令订阅指定名称的频道外,还可以使用PSUBSCRIBE命令订
阅指定的规则。规则支持glob风格通配符格式(见3.1节),下面我们新打开一个redis-cli实例C
进行演示:
redis C>PSUBSCRIBE channel.?*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel.?*"
3) (integer) 1
规则channel.?*可以匹配channel.1和channel.10,但不会匹配channel.。
PUNSUBSCRIBE命令可以退订指定的规则,用法是PUNSUBSCRIBE [pattern[pattern …]],如果没有参数则会退订所有规则。
注意 使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道;同样UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则。
1. 获得符合规则的键名列表
KEYS pattern
pattern支持glob风格通配符格式,具体规则如表3-1所示。
pattern支持glob风格通配符格式,具体规则如表3-1所示。
注意 KEYS命令需要遍历Redis中的所有键,当键的数量较多时会影响性能,不建议在生产环境中使用。
2.判断一个键是否存在
EXISTS key
如果键存在则返回整数类型1,否则返回0.
EXISTS key
如果键存在则返回整数类型1,否则返回0.
3.删除键
DEL key [key …]
可以删除一个或多个键,返回值是删除的键的个数。
DEL key [key …]
可以删除一个或多个键,返回值是删除的键的个数。
4.获得键值的数据类型
TYPE key
TYPE命令用来获得键值的数据类型,返回值可能是string(字符串类型)、hash(散列类
型)、list(列表类型)、set(集合类型)、zset(有序集合类型)。
TYPE key
TYPE命令用来获得键值的数据类型,返回值可能是string(字符串类型)、hash(散列类
型)、list(列表类型)、set(集合类型)、zset(有序集合类型)。
二、String类型命令
1.赋值与取值
SET key value
GET key
例如:
redis>SET key hello
OK
想要读取键值则更简单:
redis>GET key
"hello"
当键不存在时会返回空结果(nil)。
SET key value
GET key
例如:
redis>SET key hello
OK
想要读取键值则更简单:
redis>GET key
"hello"
当键不存在时会返回空结果(nil)。
2.递增数字
INCR key
前面说过字符串类型可以存储任何形式的字符串,当存储的字符串是整数形式时,Redis
提供了一个实用的命令INCR,其作用是让当前键值递增,并返回递增后的值,用法为:
redis>INCR num
(integer) 1
redis>INCR num
(integer) 2
当要操作的键不存在时会默认键值为0,所以第一次递增后的结果是1。当键值不是整数
时Redis会提示错误:
redis>SET foo lorem
OK
redis>INCR foo
(error) ERR value is not an integer or out of range
INCR key
前面说过字符串类型可以存储任何形式的字符串,当存储的字符串是整数形式时,Redis
提供了一个实用的命令INCR,其作用是让当前键值递增,并返回递增后的值,用法为:
redis>INCR num
(integer) 1
redis>INCR num
(integer) 2
当要操作的键不存在时会默认键值为0,所以第一次递增后的结果是1。当键值不是整数
时Redis会提示错误:
redis>SET foo lorem
OK
redis>INCR foo
(error) ERR value is not an integer or out of range
提示 Redis对于键的命名并没有强制的要求,但比较好的实践是用“对象类型:对象
ID:对象属性”来命名一个键,如使用键user:1:friends来存储ID为1的用户的好友列表。对于
多个单词则推荐使用“.”分隔,一方面是沿用以前的习惯(Redis以前版本的键名不能包含
空格等特殊字符),另一方面是在redis-cli中容易输入,无需使用双引号包裹。
ID:对象属性”来命名一个键,如使用键user:1:friends来存储ID为1的用户的好友列表。对于
多个单词则推荐使用“.”分隔,一方面是沿用以前的习惯(Redis以前版本的键名不能包含
空格等特殊字符),另一方面是在redis-cli中容易输入,无需使用双引号包裹。
3.增加指定的整数
INCRBY key increment
INCRBY命令与INCR命令基本一样,只不过INCRBY可以通过increment参数指定一次增加的
数值,如:
redis>INCRBY bar 2
(integer) 2
INCRBY key increment
INCRBY命令与INCR命令基本一样,只不过INCRBY可以通过increment参数指定一次增加的
数值,如:
redis>INCRBY bar 2
(integer) 2
4.减少指定的整数
DECR key
DECRBY key decrement
DECR命令与INCR命令用法相同,只不过是让键值递减,例如:
redis>DECR bar
(integer)4
DECR key
DECRBY key decrement
DECR命令与INCR命令用法相同,只不过是让键值递减,例如:
redis>DECR bar
(integer)4
5.增加指定浮点数
INCRBYFLOAT key increment
INCRBYFLOAT 命令类似INCRBY命令,差别是前者可以递增一个双精度浮点数,如:
redis>INCRBYFLOAT bar 2.7
"6.7"
6.向尾部追加值
APPEND key value
APPEND作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value,即相
当于SET key value。返回值是追加后字符串的总长度。例如:
redis>SET key hello
OK
redis>APPEND key " world!"
(integer) 12
7.获取字符串长度
STRLEN key
STRLEN命令返回键值的长度,如果键不存在则返回0。
INCRBYFLOAT key increment
INCRBYFLOAT 命令类似INCRBY命令,差别是前者可以递增一个双精度浮点数,如:
redis>INCRBYFLOAT bar 2.7
"6.7"
6.向尾部追加值
APPEND key value
APPEND作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value,即相
当于SET key value。返回值是追加后字符串的总长度。例如:
redis>SET key hello
OK
redis>APPEND key " world!"
(integer) 12
7.获取字符串长度
STRLEN key
STRLEN命令返回键值的长度,如果键不存在则返回0。
8.同时获得/设置多个键值
MGET key [key …]
MSET key value [key value …]
例如:
redis>MSET key1 v1 key2 v2 key3 v3
OK
redis>GET key2
"v2"
redis>MGET key1 key3
1) "v1"
2) "v3"
MGET key [key …]
MSET key value [key value …]
例如:
redis>MSET key1 v1 key2 v2 key3 v3
OK
redis>GET key2
"v2"
redis>MGET key1 key3
1) "v1"
2) "v3"
9.位操作
GETBIT key offset
GETBIT命令可以获得一个字符串类型键指定位置的二进制位的值(0或1),索引从0开始
redis>GETBIT foo 0
如果需要获取的二进制位的索引超出了键值的二进制位的实际长度则默认位值是0
SETBIT key offset value
SETBIT 命令可以设置字符串类型键指定位置的二进制位的值,返回值是该位置的旧值。
redis>SETBIT foo 6 0
(integer) 1
如果要设置的位置超过了键值的二进制位的长度,SETBIT命令会自动将中间的二进制位
设置为0,同理设置一个不存在的键的指定二进制位的值会自动将其前面的位赋值为0
BITCOUNT key [start] [end]
BITCOUNT命令可以获得字符串类型键中值是1的二进制位个数,例如:
redis>BITCOUNT foo
(integer)10
BITOP operation destkey key [key …]
BITOP命令可以对多个字符串类型键进行位运算,并将结果存储在destkey参数指定的键
中。BITOP命令支持的运算操作有AND、OR、XOR 和NOT。如我们可以对bar和aar进行OR运
算:
redis>SET foo1 bar
OK
redis>SET foo2 aar
OK
redis>BITOP OR res foo1 foo2
(integer) 3
redis>GET res
"car"
GETBIT key offset
GETBIT命令可以获得一个字符串类型键指定位置的二进制位的值(0或1),索引从0开始
redis>GETBIT foo 0
如果需要获取的二进制位的索引超出了键值的二进制位的实际长度则默认位值是0
SETBIT key offset value
SETBIT 命令可以设置字符串类型键指定位置的二进制位的值,返回值是该位置的旧值。
redis>SETBIT foo 6 0
(integer) 1
如果要设置的位置超过了键值的二进制位的长度,SETBIT命令会自动将中间的二进制位
设置为0,同理设置一个不存在的键的指定二进制位的值会自动将其前面的位赋值为0
BITCOUNT key [start] [end]
BITCOUNT命令可以获得字符串类型键中值是1的二进制位个数,例如:
redis>BITCOUNT foo
(integer)10
BITOP operation destkey key [key …]
BITOP命令可以对多个字符串类型键进行位运算,并将结果存储在destkey参数指定的键
中。BITOP命令支持的运算操作有AND、OR、XOR 和NOT。如我们可以对bar和aar进行OR运
算:
redis>SET foo1 bar
OK
redis>SET foo2 aar
OK
redis>BITOP OR res foo1 foo2
(integer) 3
redis>GET res
"car"
三、散列类型
1.赋值与取值
HSET key field value
HGET key field
HSET命令用来给字段赋值,而HGET命令用来获得字段的值。
用法如下:
redis>HSET car name BMW
(integer) 1
redis>HGET car name
"BMW"
HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字
段是否存在来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作
时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前字段已经存
在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。
HSET key field value
HGET key field
HSET命令用来给字段赋值,而HGET命令用来获得字段的值。
用法如下:
redis>HSET car name BMW
(integer) 1
redis>HGET car name
"BMW"
HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字
段是否存在来决定要执行的是插入操作(update)还是更新操作(insert)。当执行的是插入操作
时(即之前字段不存在)HSET命令会返回1,当执行的是更新操作时(即之前字段已经存
在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。
HMSET key field value [field value …]
HMGET key field [field …]
HGETALL key
当需要同时设置多个字段的值时,可以使用HMSET命令。
例如:
HMSET key field1 value1 field2 value2
相应地,HMGET命令可以同时获得多个字段的值:
redis>HMGET car price name
如果想获取键中所有字段和字段值却不知道键中有哪些字段时, 应该使用HGETALL命令
redis>HGETALL car
1) "price"
2) "500"
3) "name"
4) "BMW"
HMGET key field [field …]
HGETALL key
当需要同时设置多个字段的值时,可以使用HMSET命令。
例如:
HMSET key field1 value1 field2 value2
相应地,HMGET命令可以同时获得多个字段的值:
redis>HMGET car price name
如果想获取键中所有字段和字段值却不知道键中有哪些字段时, 应该使用HGETALL命令
redis>HGETALL car
1) "price"
2) "500"
3) "name"
4) "BMW"
2.判断字段是否存在
HEXISTS key field
HEXISTS命令用来判断一个字段是否存在。如果存在则返回1,否则返回0(如果键不存在
也会返回0)。
redis>HEXISTS car model
(integer) 0
3.当字段不存在时赋值
HSETNX key field value
HSETNX① 命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行
任何操作
4.增加数字
HINCRBY key field increment
使字段值增加指定的整数
redis>HINCRBY person score 60
(integer) 60
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值
为“0”。命令的返回值是增值后的字段值。
5.删除字段
HDEL key field [field …]
HDEL命令可以删除一个或多个字段,返回值是被删除的字段个数
6.只获取字段名或字段值
HKEYS key
HVALS key
有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用HKEYS命令
,HVALS命令用来获得键中所有字段值
7.获得字段数量
HLEN key
HEXISTS key field
HEXISTS命令用来判断一个字段是否存在。如果存在则返回1,否则返回0(如果键不存在
也会返回0)。
redis>HEXISTS car model
(integer) 0
3.当字段不存在时赋值
HSETNX key field value
HSETNX① 命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行
任何操作
4.增加数字
HINCRBY key field increment
使字段值增加指定的整数
redis>HINCRBY person score 60
(integer) 60
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值
为“0”。命令的返回值是增值后的字段值。
5.删除字段
HDEL key field [field …]
HDEL命令可以删除一个或多个字段,返回值是被删除的字段个数
6.只获取字段名或字段值
HKEYS key
HVALS key
有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用HKEYS命令
,HVALS命令用来获得键中所有字段值
7.获得字段数量
HLEN key
四、列表类型(list)
列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时
间复杂度为0(1)
1.向列表两端增加元素
LPUSH key value [value …]
LPUSH命令用来向列表左边增加元素,返回值表示增加元素后列表的长度。
redis>LPUSH numbers 1
(integer) 1
RPUSH key value [value …]
列表右边增加元素, 其用法和LPUSH命令一样
2.从列表两端弹出元素
LPOP key
RPOP key
有进有出,LPOP命令可以从列表左边弹出一个元素。LPOP命令执行两步操作:第一步是
将列表左边的元素从列表中移除,第二步是返回被移除的元素值。
同样,RPOP命令可以从列表右边弹出一个元素
结合上面提到的4个命令可以使用列表类型来模拟栈和队列的操作:如果想把列表当做
栈,则搭配使用LPUSH和
3.获取列表中元素的个数
LLEN key
当键不存在时LLEN会返回0
4.获得列表片段
LRANGE key start stop
LRANGE命令是列表类型最常用的命令之一,它能够获得列表中的某一片段。LRANGE命
令将返回索引从start到stop之间的所有元素(包含两端的元素),LRANGE命令在取得列表片段的同时不会像LPOP一样删除该片段。Redis的列表起始索引为0
redis>LRANGE numbers 0 2
1) "2"
2) "1"
3) "0"
LRANGE命令也支持负索引,表示从右边开始计算序数,如"-1"表示最右边第一个元
素,"-2"表示最右边第二个元素,依次类推
显然,LRANGE numbers 0 -1可以获取列表中的所有元素。另外一些特殊情况如下。
(1)如果start的索引位置比stop的索引位置靠后,则会返回空列表。
(2)如果stop大于实际的索引范围,则会返回到列表最右边的元素
5.删除列表中指定的值
LREM key count value
LREM命令会删除列表中前count个值为value的元素,返回值是实际删除的元素个数。根
据count值的不同,LREM命令的执行方式会略有差异:
●当count>0时LREM命令会从列表左边开始删除前count个值为value的元素;
●当count<0时LREM 命令会从列表右边开始删除前|count|个值为value的元素;
●当count=0是LREM命令会删除所有值为value的元素。
列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时
间复杂度为0(1)
1.向列表两端增加元素
LPUSH key value [value …]
LPUSH命令用来向列表左边增加元素,返回值表示增加元素后列表的长度。
redis>LPUSH numbers 1
(integer) 1
RPUSH key value [value …]
列表右边增加元素, 其用法和LPUSH命令一样
2.从列表两端弹出元素
LPOP key
RPOP key
有进有出,LPOP命令可以从列表左边弹出一个元素。LPOP命令执行两步操作:第一步是
将列表左边的元素从列表中移除,第二步是返回被移除的元素值。
同样,RPOP命令可以从列表右边弹出一个元素
结合上面提到的4个命令可以使用列表类型来模拟栈和队列的操作:如果想把列表当做
栈,则搭配使用LPUSH和
3.获取列表中元素的个数
LLEN key
当键不存在时LLEN会返回0
4.获得列表片段
LRANGE key start stop
LRANGE命令是列表类型最常用的命令之一,它能够获得列表中的某一片段。LRANGE命
令将返回索引从start到stop之间的所有元素(包含两端的元素),LRANGE命令在取得列表片段的同时不会像LPOP一样删除该片段。Redis的列表起始索引为0
redis>LRANGE numbers 0 2
1) "2"
2) "1"
3) "0"
LRANGE命令也支持负索引,表示从右边开始计算序数,如"-1"表示最右边第一个元
素,"-2"表示最右边第二个元素,依次类推
显然,LRANGE numbers 0 -1可以获取列表中的所有元素。另外一些特殊情况如下。
(1)如果start的索引位置比stop的索引位置靠后,则会返回空列表。
(2)如果stop大于实际的索引范围,则会返回到列表最右边的元素
5.删除列表中指定的值
LREM key count value
LREM命令会删除列表中前count个值为value的元素,返回值是实际删除的元素个数。根
据count值的不同,LREM命令的执行方式会略有差异:
●当count>0时LREM命令会从列表左边开始删除前count个值为value的元素;
●当count<0时LREM 命令会从列表右边开始删除前|count|个值为value的元素;
●当count=0是LREM命令会删除所有值为value的元素。
6.获得/设置指定索引的元素值
LINDEX key index
如果要将列表类型当作数组来用,LINDEX命令是必不可少的。LINDEX命令用来返回指
定索引的元素,索引从0开始。
redis>LINDEX numbers 1
"7"
7. LSET key index value
LSET是另一个通过索引操作列表的命令,它会将索引为index的元素赋值为value。例如:
redis>LSET numbers 1 7
OK
8.只保留列表指定片段
LTRIM key start end
LTRIM命令可以删除指定索引范围之外的所有元素,其指定列表范围的方法和LRANGE
命令相同。就像这样:
redis>LRANGE numbers 0 1
1) "1"
2) "2"
3) "7"
4) "3"
"0"
redis>LTRIM numbers 1 2
OK
redis>LRANGE numbers 0 1
1) "2"
2) "7"
9.向列表中插入元素
LINSERT key BEFORE|AFTER pivot value
LINSERT命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是
BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。
LINSERT命令的返回值是插入后列表的元素个数。示例如下:
redis>LINSERT numbers AFTER 7 3
4.将元素从一个列表转到另一个列表R
RPOPLPUSH source destination
RPOPLPUSH是个很有意思的命令,从名字就可以看出它的功能:先执行RPOP命令再执行
LPUSH 命令。RPOPLPUSH命令会先从source列表类型键的右边弹出一个元素,然后将其加入
到destination列表类型键的左边,并返回这个元素的值,整个过程是原子的。
LINDEX key index
如果要将列表类型当作数组来用,LINDEX命令是必不可少的。LINDEX命令用来返回指
定索引的元素,索引从0开始。
redis>LINDEX numbers 1
"7"
7. LSET key index value
LSET是另一个通过索引操作列表的命令,它会将索引为index的元素赋值为value。例如:
redis>LSET numbers 1 7
OK
8.只保留列表指定片段
LTRIM key start end
LTRIM命令可以删除指定索引范围之外的所有元素,其指定列表范围的方法和LRANGE
命令相同。就像这样:
redis>LRANGE numbers 0 1
1) "1"
2) "2"
3) "7"
4) "3"
"0"
redis>LTRIM numbers 1 2
OK
redis>LRANGE numbers 0 1
1) "2"
2) "7"
9.向列表中插入元素
LINSERT key BEFORE|AFTER pivot value
LINSERT命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是
BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。
LINSERT命令的返回值是插入后列表的元素个数。示例如下:
redis>LINSERT numbers AFTER 7 3
4.将元素从一个列表转到另一个列表R
RPOPLPUSH source destination
RPOPLPUSH是个很有意思的命令,从名字就可以看出它的功能:先执行RPOP命令再执行
LPUSH 命令。RPOPLPUSH命令会先从source列表类型键的右边弹出一个元素,然后将其加入
到destination列表类型键的左边,并返回这个元素的值,整个过程是原子的。
五、集合(set)
在集合中的每个元素都是不同的,且没有顺序。一个
集合类型(set)键可以存储至多232-1个字符串。
集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合
类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是
0(1)。
类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是
0(1)。
1.增加/删除元素
SADD key member [member …]
SREM key member [member …]
SADD命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。因为在一个
集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。本
命令的返回值是成功加入的元素数量(忽略的元素不计算在内)。例如:
redis>SADD letters a
(integer) 1
redis> SADD letters a b c
(integer) 2
SREM命令用来从集合中删除一个或多个元素,并返回删除成功的个数,例如:
redis>SREM letters c d
(integer) 1
由于元素“d”在集合中不存在,所以只删除了一个元素,返回值为1。
2.获得集合中的所有元素
SMEMBERS key
SMEMBERS命令会返回集合中的所有元素,例如:
redis>SMEMBERS letters
1) "b"
2) "a"
3.判断元素是否在集合中
SISMEMBER key member
判断一个元素是否在集合中是一个时间复杂度为0(1)的操作,无论集合中有多少个元
素,SISMEMBER命令始终可以极快地返回结果。当值存在时SISMEMBER命令返回1,当值不
存在或键不存在时返回0,例如:
redis>SISMEMBER letters a
(integer) 1
4.集合间运算
SDIFF key [key …]
SINTER key [key …]
SUNION key [key …]
接下来要介绍的3个命令都是用来进行多个集合间运算的。
(1)SDIFF命令用来对多个集合执行差集运算。集合A与集合B的差集表示为A-B,代表所
有属于A且不属于B的元素构成的集合(如图3-13所示),即A-B={x|x∈A且x∈/B}。
例如:{1, 2, 3}-{2, 3, 4}={1}
redis>SDIFF setA setB
1) "1"
SDIFF 命令支持同时传入多个键(计算顺序是先计算setA-setB,再计算结果与setC的差集。),例如:
redis>SDIFF setA setB setC
1 ) "1"
(2)SINTER命令用来对多个集合执行交集运算。集合A与集合B的交集表示为A∩B,代表
所有属于A且属于B的元素构成的集合(如图3-14所示),即A∩B={x|x∈A且x∈B}。例如:
{1, 2, 3}∩{2, 3, 4}={2, 3}
SINTER命令的使用方法如下:
redis>SINTER setA setB
1) "2"
2) "3"
SINTER命令同样支持同时传入多个键,如:
redis>SINTER setA setB setC
1) "2"
2) "3"
(3)SUNION命令用来对多个集合执行并集运算。集合A与集合B的并集表示为AUB,代表
所有属于A或属于B的元素构成的集合(如图3-15所示),即AUB={x|x∈A 或x∈B}。例如:
{1, 2, 3}∪{2, 3, 4}={1, 2, 3, 4}
SUNION命令的使用方法如下:
redis>SUNION setA setB
1) "1"
2) "2"
3) "3"
4) "4"
SUNION命令同样支持同时传入多个键,例如:
redis>SUNION setA setB setC
1) "1"
2) "2"
3) "3"
4) "4"
SADD key member [member …]
SREM key member [member …]
SADD命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。因为在一个
集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。本
命令的返回值是成功加入的元素数量(忽略的元素不计算在内)。例如:
redis>SADD letters a
(integer) 1
redis> SADD letters a b c
(integer) 2
SREM命令用来从集合中删除一个或多个元素,并返回删除成功的个数,例如:
redis>SREM letters c d
(integer) 1
由于元素“d”在集合中不存在,所以只删除了一个元素,返回值为1。
2.获得集合中的所有元素
SMEMBERS key
SMEMBERS命令会返回集合中的所有元素,例如:
redis>SMEMBERS letters
1) "b"
2) "a"
3.判断元素是否在集合中
SISMEMBER key member
判断一个元素是否在集合中是一个时间复杂度为0(1)的操作,无论集合中有多少个元
素,SISMEMBER命令始终可以极快地返回结果。当值存在时SISMEMBER命令返回1,当值不
存在或键不存在时返回0,例如:
redis>SISMEMBER letters a
(integer) 1
4.集合间运算
SDIFF key [key …]
SINTER key [key …]
SUNION key [key …]
接下来要介绍的3个命令都是用来进行多个集合间运算的。
(1)SDIFF命令用来对多个集合执行差集运算。集合A与集合B的差集表示为A-B,代表所
有属于A且不属于B的元素构成的集合(如图3-13所示),即A-B={x|x∈A且x∈/B}。
例如:{1, 2, 3}-{2, 3, 4}={1}
redis>SDIFF setA setB
1) "1"
SDIFF 命令支持同时传入多个键(计算顺序是先计算setA-setB,再计算结果与setC的差集。),例如:
redis>SDIFF setA setB setC
1 ) "1"
(2)SINTER命令用来对多个集合执行交集运算。集合A与集合B的交集表示为A∩B,代表
所有属于A且属于B的元素构成的集合(如图3-14所示),即A∩B={x|x∈A且x∈B}。例如:
{1, 2, 3}∩{2, 3, 4}={2, 3}
SINTER命令的使用方法如下:
redis>SINTER setA setB
1) "2"
2) "3"
SINTER命令同样支持同时传入多个键,如:
redis>SINTER setA setB setC
1) "2"
2) "3"
(3)SUNION命令用来对多个集合执行并集运算。集合A与集合B的并集表示为AUB,代表
所有属于A或属于B的元素构成的集合(如图3-15所示),即AUB={x|x∈A 或x∈B}。例如:
{1, 2, 3}∪{2, 3, 4}={1, 2, 3, 4}
SUNION命令的使用方法如下:
redis>SUNION setA setB
1) "1"
2) "2"
3) "3"
4) "4"
SUNION命令同样支持同时传入多个键,例如:
redis>SUNION setA setB setC
1) "1"
2) "2"
3) "3"
4) "4"
5.获得集合中元素个数
SCARD key
SCARD命令用来获得集合中的元素个数,例如:
redis>SCARD letters
(integer) 2
6.进行集合运算并将结果存储
SDIFFSTORE destination key [key …]
SINTERSTORE destination key [key …]
SUNIONSTORE destination key [key …]
SDIFFSTORE命令和SDIFF命令功能一样,唯一的区别就是前者不会直接返回运算结果,
而是将结果存储在destination键中。
SDIFFSTORE命令常用于需要进行多步集合运算的场景中,如需要先计算差集再将结果
和其他键计算交集。
SINTERSTORE和SUNIONSTORE命令与之类似
7.随机获得集合中的元素
SRANDMEMBER key [count]
SRANDMEMBER命令用来随机从集合中获取一个元素,如:
redis>SRANDMEMBER letters
"a"
还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。
(1)当count为正数时,SRANDMEMBER会随机从集合里获得count个不重复的元素。如果
count的值大于集合中的元素个数,则SRANDMEMBER会返回集合中的全部元素。
(2)当count为负数时,SRANDMEMBER会随机从集合里获得|count|个的元素,这些元素有
可能相同。
8.从集合中弹出一个元素
SPOP key
3.4节中我们学习过LPOP命令,作用是从列表左边弹出一个元素(即返回元素的值并删除
它)。SPOP命令的作用与之类似,但由于集合类型的元素是无序的,所以SPOP命令会从集合中
随机选择一个元素弹出。
例如:
redis>SPOP letters
"b"
SCARD key
SCARD命令用来获得集合中的元素个数,例如:
redis>SCARD letters
(integer) 2
6.进行集合运算并将结果存储
SDIFFSTORE destination key [key …]
SINTERSTORE destination key [key …]
SUNIONSTORE destination key [key …]
SDIFFSTORE命令和SDIFF命令功能一样,唯一的区别就是前者不会直接返回运算结果,
而是将结果存储在destination键中。
SDIFFSTORE命令常用于需要进行多步集合运算的场景中,如需要先计算差集再将结果
和其他键计算交集。
SINTERSTORE和SUNIONSTORE命令与之类似
7.随机获得集合中的元素
SRANDMEMBER key [count]
SRANDMEMBER命令用来随机从集合中获取一个元素,如:
redis>SRANDMEMBER letters
"a"
还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。
(1)当count为正数时,SRANDMEMBER会随机从集合里获得count个不重复的元素。如果
count的值大于集合中的元素个数,则SRANDMEMBER会返回集合中的全部元素。
(2)当count为负数时,SRANDMEMBER会随机从集合里获得|count|个的元素,这些元素有
可能相同。
8.从集合中弹出一个元素
SPOP key
3.4节中我们学习过LPOP命令,作用是从列表左边弹出一个元素(即返回元素的值并删除
它)。SPOP命令的作用与之类似,但由于集合类型的元素是无序的,所以SPOP命令会从集合中
随机选择一个元素弹出。
例如:
redis>SPOP letters
"b"
六、有序集合类型(sorted set)
介绍:
在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们
不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能够获得分数最高
(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元
素都是不同的,但是它们的分数却可以相同。
有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得它们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问
中间数据的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的
应用。
(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分
的数据速度也很快(时间复杂度是O(log(N)))。
(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分
数)。
(4)有序集合要比列表类型更耗费内存。
1.增加元素
ZADD key score member [score member …]
ZADD命令用来向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会
用新的分数替换原有的分数。ZADD命令的返回值是新加入到集合中的元素个数(不包含之前
已经存在的元素)。
例如:
redis>ZADD scoreboard 89 Tom 67 Peter 100 David
(integer) 3
分数不仅可以是整数,还支持双精度浮点数:
2.获得元素的分数
ZSCORE key member
示例如下:
redis>ZSCORE scoreboard Tom
"89"
3.获得排名在某个范围的元素列表
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
ZRANGE命令会按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包
含两端的元素)。ZRANGE命令与LRANGE命令十分相似,如索引都是从0开始,负数代表从后
向前查找(-1表示最后一个元素)。就像这样:
redis>ZRANGE scoreboard 0 2
1) "Peter"
2) "Tom"
3) "David"
如果需要同时获得元素的分数的话可以在ZRANGE命令的尾部加上WITHSCORES参数,
这时返回的数据格式就从“元素1, 元素2, …, 元素n”变为了“元素1, 分数1, 元素2, 分数2, …, 元
素n, 分数n”,例如:
redis>ZRANGE scoreboard 0 -1 WITHSCORES
1) "Peter"
2) "76"
ZREVRANGE命令和ZRANGE的唯一不同在于ZREVRANGE命令是按照元素分数从大到小的顺序给出结果的。
4.获得指定分数范围的元素
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZRANGEBYSCORE命令参数虽然多,但是都很好理解。该命令按照元素分数从小到大的
顺序返回分数在min和max之间(包含min和max)的元素:
redis>ZRANGEBYSCORE scoreboard 80 100
1) "Tom"
2) "David"
如果希望分数范围不包含端点值,可以在分数前加上“(”符号。例如,希望返回80分到100
分的数据,可以含80分,但不包含100分,则稍微修改一下上面的命令即可:
redis>ZRANGEBYSCORE scoreboard 80 (100
1) "Tom"
min和max还支持无穷大,同ZADD命令一样,-inf 和+inf分别表示负无穷和正无穷。比如你
希望得到所有分数高于80分(不包含80分)的人的名单,但你却不知道最高分是多少(虽然有些
背离现实,但是为了叙述方便,这里假设可以获得的分数是无上限的),这时就可以用上+inf
了:
redis>ZRANGEBYSCORE scoreboard (80 +inf
1) "Tom"
2) "David"
WITHSCORES参数的用法与ZRANGE命令一样,不再赘述。
了解SQL语句的读者对LIMIT offset count应该很熟悉,在本命令中LIMIT offset count与SQL
中的用法基本相同,即在获得的元素列表的基础上向后偏移offset个元素,并且只获取前count
个元素。
例如:
想获得分数高于60分的从第二个人开始的3个人:
redis>ZRANGEBYSCORE scoreboard 60 +inf LIMIT 1 3
1) "Peter"
2) "Tom"
3) "Wendy"
5.增加某个元素的分数
Z INCRBY key increment member
ZINCRBY命令可以增加一个元素的分数,返回值是更改后的分数。例如,想给Jerry加4分:
redis>ZINCRBY scoreboard 4 Jerry
"60"
increment也可以是个负数表示减分,例如,给Jerry减4分:
redis>ZINCRBY scoreboard -4 Jerry
" 56"
如果指定的元素不存在,Redis在执行命令前会先建立它并将它的分数赋为0再执行操作。
介绍:
在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们
不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能够获得分数最高
(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元
素都是不同的,但是它们的分数却可以相同。
有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得它们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问
中间数据的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的
应用。
(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分
的数据速度也很快(时间复杂度是O(log(N)))。
(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分
数)。
(4)有序集合要比列表类型更耗费内存。
1.增加元素
ZADD key score member [score member …]
ZADD命令用来向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会
用新的分数替换原有的分数。ZADD命令的返回值是新加入到集合中的元素个数(不包含之前
已经存在的元素)。
例如:
redis>ZADD scoreboard 89 Tom 67 Peter 100 David
(integer) 3
分数不仅可以是整数,还支持双精度浮点数:
2.获得元素的分数
ZSCORE key member
示例如下:
redis>ZSCORE scoreboard Tom
"89"
3.获得排名在某个范围的元素列表
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
ZRANGE命令会按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包
含两端的元素)。ZRANGE命令与LRANGE命令十分相似,如索引都是从0开始,负数代表从后
向前查找(-1表示最后一个元素)。就像这样:
redis>ZRANGE scoreboard 0 2
1) "Peter"
2) "Tom"
3) "David"
如果需要同时获得元素的分数的话可以在ZRANGE命令的尾部加上WITHSCORES参数,
这时返回的数据格式就从“元素1, 元素2, …, 元素n”变为了“元素1, 分数1, 元素2, 分数2, …, 元
素n, 分数n”,例如:
redis>ZRANGE scoreboard 0 -1 WITHSCORES
1) "Peter"
2) "76"
ZREVRANGE命令和ZRANGE的唯一不同在于ZREVRANGE命令是按照元素分数从大到小的顺序给出结果的。
4.获得指定分数范围的元素
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZRANGEBYSCORE命令参数虽然多,但是都很好理解。该命令按照元素分数从小到大的
顺序返回分数在min和max之间(包含min和max)的元素:
redis>ZRANGEBYSCORE scoreboard 80 100
1) "Tom"
2) "David"
如果希望分数范围不包含端点值,可以在分数前加上“(”符号。例如,希望返回80分到100
分的数据,可以含80分,但不包含100分,则稍微修改一下上面的命令即可:
redis>ZRANGEBYSCORE scoreboard 80 (100
1) "Tom"
min和max还支持无穷大,同ZADD命令一样,-inf 和+inf分别表示负无穷和正无穷。比如你
希望得到所有分数高于80分(不包含80分)的人的名单,但你却不知道最高分是多少(虽然有些
背离现实,但是为了叙述方便,这里假设可以获得的分数是无上限的),这时就可以用上+inf
了:
redis>ZRANGEBYSCORE scoreboard (80 +inf
1) "Tom"
2) "David"
WITHSCORES参数的用法与ZRANGE命令一样,不再赘述。
了解SQL语句的读者对LIMIT offset count应该很熟悉,在本命令中LIMIT offset count与SQL
中的用法基本相同,即在获得的元素列表的基础上向后偏移offset个元素,并且只获取前count
个元素。
例如:
想获得分数高于60分的从第二个人开始的3个人:
redis>ZRANGEBYSCORE scoreboard 60 +inf LIMIT 1 3
1) "Peter"
2) "Tom"
3) "Wendy"
5.增加某个元素的分数
Z INCRBY key increment member
ZINCRBY命令可以增加一个元素的分数,返回值是更改后的分数。例如,想给Jerry加4分:
redis>ZINCRBY scoreboard 4 Jerry
"60"
increment也可以是个负数表示减分,例如,给Jerry减4分:
redis>ZINCRBY scoreboard -4 Jerry
" 56"
如果指定的元素不存在,Redis在执行命令前会先建立它并将它的分数赋为0再执行操作。
6.获得集合中元素的数量
ZCARD key
例如:
redis>ZCARD scoreboard
(integer) 6
7.获得指定分数范围內的元素个数
ZCOUNT key min max
例如:
redis>ZCOUNT scoreboard 90 100
(integer) 2
ZCOUNT命令的min和max参数的特性与ZRANGEBYSCORE命令中的一样:
redis>ZCOUNT scoreboard (89 +inf
(integer) 2
8.删除一个或多个元素
ZREM key member [member …]
ZREM命令的返回值是成功删除的元素数量(不包含本来就不存在的元素)。
redis>ZREM scoreboard Wendy
(integer) 1
9.按照排名范围删除元素
ZREMRANGEBYRANK key start stop
ZREMRANGEBYRANK命令按照元素分数从小到大的顺序(即索引0表示最小的值)删除
处在指定排名范围内的所有元素,并返回删除的元素数量。如:
redis>ZREMRANGEBYRANK testRem 0 2
9.按照分数范围删除元素
ZREMRANGEBYSCORE key min max
ZREMRANGEBYSCORE命令会删除指定分数范围内的所有元素,参数min和max的特性
和ZRANGEBYSCORE命令中的一样。返回值是删除的元素数量。如:
redis>ZREMRANGEBYSCORE testRem (4 5
(integer) 1
10.获得元素的排名
ZRANK key member
ZREVRANK key member
ZRANK命令会按照元素分数从小到大的顺序获得指定的元素的排名(从0开始,即分数最
小的元素排名为0)。如:
redis>ZRANK scoreboard Peter
(integer) 0
ZREVRANK命令则相反(分数最大的元素排名为0)
11.计算有序集合的交集
ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]]
[AGREGATE SUM|MIN|MAX]
ZINTERSTORE命令用来计算多个有序集合的交集并将结果存储在destination键中(同样
以有序集合类型存储),返回值为destination键中的元素个数。
destination键中元素的分数是由AGGREGATE参数决定的。
(1)当AGGREGATE是SUM时(也就是默认值),destination键中元素的分数是每个参与计
算的集合中该元素分数的和。例如:
redis>ZADD sortedSets1 1 a 2 b
(integer) 2
redis>ZADD sortedSets2 10 a 20 b
(integer) 2
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "11"
3) "b"
4) "22"
(2)当AGGREGATE是MIN时,destination键中元素的分数是每个参与计算的集合中该元
素分数的最小值。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 AGGREGATE MIN
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "1"
3) "b"
4) "2"
(3)当AGGREGATE是MAX时,destination键中元素的分数是每个参与计算的集合中该元
素分数的最大值。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 AGGREGATE MAX
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "10"
3) "b"
4)"20"
ZINTERSTORE命令还能够通过WEIGHTS参数设置每个集合的权重,每个集合在参与计
算时元素的分数会被乘上该集合的权重。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 WEIGHTS 1 0.1
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "2"
3) "b"
4) "4"
另外还有一个命令与ZINTERSTORE命令的用法一样,名为ZUNIONSTORE,它的作用是
计算集合间的并集,这里不再赘述。
ZCARD key
例如:
redis>ZCARD scoreboard
(integer) 6
7.获得指定分数范围內的元素个数
ZCOUNT key min max
例如:
redis>ZCOUNT scoreboard 90 100
(integer) 2
ZCOUNT命令的min和max参数的特性与ZRANGEBYSCORE命令中的一样:
redis>ZCOUNT scoreboard (89 +inf
(integer) 2
8.删除一个或多个元素
ZREM key member [member …]
ZREM命令的返回值是成功删除的元素数量(不包含本来就不存在的元素)。
redis>ZREM scoreboard Wendy
(integer) 1
9.按照排名范围删除元素
ZREMRANGEBYRANK key start stop
ZREMRANGEBYRANK命令按照元素分数从小到大的顺序(即索引0表示最小的值)删除
处在指定排名范围内的所有元素,并返回删除的元素数量。如:
redis>ZREMRANGEBYRANK testRem 0 2
9.按照分数范围删除元素
ZREMRANGEBYSCORE key min max
ZREMRANGEBYSCORE命令会删除指定分数范围内的所有元素,参数min和max的特性
和ZRANGEBYSCORE命令中的一样。返回值是删除的元素数量。如:
redis>ZREMRANGEBYSCORE testRem (4 5
(integer) 1
10.获得元素的排名
ZRANK key member
ZREVRANK key member
ZRANK命令会按照元素分数从小到大的顺序获得指定的元素的排名(从0开始,即分数最
小的元素排名为0)。如:
redis>ZRANK scoreboard Peter
(integer) 0
ZREVRANK命令则相反(分数最大的元素排名为0)
11.计算有序集合的交集
ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]]
[AGREGATE SUM|MIN|MAX]
ZINTERSTORE命令用来计算多个有序集合的交集并将结果存储在destination键中(同样
以有序集合类型存储),返回值为destination键中的元素个数。
destination键中元素的分数是由AGGREGATE参数决定的。
(1)当AGGREGATE是SUM时(也就是默认值),destination键中元素的分数是每个参与计
算的集合中该元素分数的和。例如:
redis>ZADD sortedSets1 1 a 2 b
(integer) 2
redis>ZADD sortedSets2 10 a 20 b
(integer) 2
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "11"
3) "b"
4) "22"
(2)当AGGREGATE是MIN时,destination键中元素的分数是每个参与计算的集合中该元
素分数的最小值。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 AGGREGATE MIN
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "1"
3) "b"
4) "2"
(3)当AGGREGATE是MAX时,destination键中元素的分数是每个参与计算的集合中该元
素分数的最大值。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 AGGREGATE MAX
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "10"
3) "b"
4)"20"
ZINTERSTORE命令还能够通过WEIGHTS参数设置每个集合的权重,每个集合在参与计
算时元素的分数会被乘上该集合的权重。例如:
redis>ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2 WEIGHTS 1 0.1
(integer) 2
redis>ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "2"
3) "b"
4) "4"
另外还有一个命令与ZINTERSTORE命令的用法一样,名为ZUNIONSTORE,它的作用是
计算集合间的并集,这里不再赘述。
七、事务(transaction)
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis的最小执行单
位,一个事务中的命令要么都执行,要么都不执行。
例如:
OK
redis>SADD "user:1:following" 2
QUEUED
redis>SADD "user:2:followers" 1
QUEUED
redis>EXEC
1) (integer) 1
2) (integer) 1
上面的代码演示了事务的使用方式。首先使用MULTI命令告诉Redis:“下面我发给你的命令属于同一个事务,你先不要执行,而是把它们暂时存起来。”Redis回答:“OK。”
而后我们发送了两个SADD命令来实现关注和被关注操作,可以看到Redis遵守了承诺,没有执行这些命令,而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。
当把所有要在同一个事务中执行的命令都发给Redis后,我们使用EXEC命令告诉Redis将等待执行的事务队列中的所有命令(即刚才所有返回QUEUED的命令)按照发送顺序依次执
行。EXEC命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客
户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
1、错误处理:
(1)语法错误。语法错误指命令不存在或者命令参数的个数不对。比如:
redis>MULTI
OK
redis>SET key value
QUEUED
redis>SET key
(error)ERR wrong number of arguments for 'set' command
redis> ERRORCOMMAND key
(error) ERR unknown command 'ERRORCOMMAND'
redis> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
跟在MULTI命令后执行了3个命令:一个是正确的命令,成功地加入事务队列;其余两个命
令都有语法错误。而只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,
连语法正确的命令也不会执行
(2)运行错误。运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合
类型的键,这种错误在实际执行之前Redis是无法发现的,所以在事务里这样的命令是会被
Redis接受并执行的。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续
执行(包括出错命令之后的命令),示例如下:
redis>MULTI
OK
redis>SET key 1
QUEUED
redis>SADD key 2
QUEUED
redis>SET key 3
QUEUED
redis>EXEC
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
redis>GET key
"3"
可见虽然SADD key 2出现了错误,但是SET key 3依然执行了。
Redis的事务没有关系数据库事务提供的回滚(rollback)① 功能。为此开发者必须在事务
执行出错后自己收拾剩下的摊子(将数据库复原回事务执行前的状态等)。
2、生存时间
在Redis中可以使用EXPIRE命令设置一个键的生存时间,
到时间后Redis会自动删除它。
EXPIRE命令的使用方法为EXPIRE key seconds,其中seconds参数表示键的生存时间,单
位是秒。如要想让session:29e3d键在15分钟后被删除:
redis>EXPIRE session:29e3d 900
(integer) 1
EXPIRE命令返回1表示设置成功,返回0则表示键不存在或设置失败。
如果想知道一个键还有多久的时间会被删除,可以使用TTL命令。返回值是键的剩余时间
(单位是秒):
redis>TTL foo
(integer) 15
当键不存在时TTL命令会返回 -2。没有为键设置生存时间(即永久存在,这是建立
一个键后的默认情况)会返回 -1
如果想取消键的生存时间设置(即将键恢复成永久的),可以使用PERSIST命令。如果生存
时间被成功清除则返回1;否则返回0(因为键不存在或键本来就是永久的):
redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>PERSIST foo
(integer) 1
redis>TTL foo
(integer) -1
除了PERSIST命令之外,使用SET或GETSET命令为键赋值也会同时清除键的生存时间,
例如:
redis>EXPIRE foo 20
(integer) 1
redis>SET foo bar
OK
redis>TTL foo
(integer) -1
其他只对键值进行操作的命令(如INCR、LPUSH、HSET、ZREM)均不会影响键的生存时间。
EXPIRE命令的seconds参数必须是整数,所以最小单位是1秒。如果想要更精确的控制键
的生存时间应该使用PEXPIRE命令,PEXPIRE命令与EXPIRE的唯一区别是前者的时间单位是
毫秒,即PEXPIRE key 1000与EXPIRE key 1等价。对应地可以用PTTL命令以毫秒为单位返回键
的剩余时间。
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis的最小执行单
位,一个事务中的命令要么都执行,要么都不执行。
例如:
OK
redis>SADD "user:1:following" 2
QUEUED
redis>SADD "user:2:followers" 1
QUEUED
redis>EXEC
1) (integer) 1
2) (integer) 1
上面的代码演示了事务的使用方式。首先使用MULTI命令告诉Redis:“下面我发给你的命令属于同一个事务,你先不要执行,而是把它们暂时存起来。”Redis回答:“OK。”
而后我们发送了两个SADD命令来实现关注和被关注操作,可以看到Redis遵守了承诺,没有执行这些命令,而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。
当把所有要在同一个事务中执行的命令都发给Redis后,我们使用EXEC命令告诉Redis将等待执行的事务队列中的所有命令(即刚才所有返回QUEUED的命令)按照发送顺序依次执
行。EXEC命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客
户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
1、错误处理:
(1)语法错误。语法错误指命令不存在或者命令参数的个数不对。比如:
redis>MULTI
OK
redis>SET key value
QUEUED
redis>SET key
(error)ERR wrong number of arguments for 'set' command
redis> ERRORCOMMAND key
(error) ERR unknown command 'ERRORCOMMAND'
redis> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
跟在MULTI命令后执行了3个命令:一个是正确的命令,成功地加入事务队列;其余两个命
令都有语法错误。而只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,
连语法正确的命令也不会执行
(2)运行错误。运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合
类型的键,这种错误在实际执行之前Redis是无法发现的,所以在事务里这样的命令是会被
Redis接受并执行的。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续
执行(包括出错命令之后的命令),示例如下:
redis>MULTI
OK
redis>SET key 1
QUEUED
redis>SADD key 2
QUEUED
redis>SET key 3
QUEUED
redis>EXEC
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
redis>GET key
"3"
可见虽然SADD key 2出现了错误,但是SET key 3依然执行了。
Redis的事务没有关系数据库事务提供的回滚(rollback)① 功能。为此开发者必须在事务
执行出错后自己收拾剩下的摊子(将数据库复原回事务执行前的状态等)。
2、生存时间
在Redis中可以使用EXPIRE命令设置一个键的生存时间,
到时间后Redis会自动删除它。
EXPIRE命令的使用方法为EXPIRE key seconds,其中seconds参数表示键的生存时间,单
位是秒。如要想让session:29e3d键在15分钟后被删除:
redis>EXPIRE session:29e3d 900
(integer) 1
EXPIRE命令返回1表示设置成功,返回0则表示键不存在或设置失败。
如果想知道一个键还有多久的时间会被删除,可以使用TTL命令。返回值是键的剩余时间
(单位是秒):
redis>TTL foo
(integer) 15
当键不存在时TTL命令会返回 -2。没有为键设置生存时间(即永久存在,这是建立
一个键后的默认情况)会返回 -1
如果想取消键的生存时间设置(即将键恢复成永久的),可以使用PERSIST命令。如果生存
时间被成功清除则返回1;否则返回0(因为键不存在或键本来就是永久的):
redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>PERSIST foo
(integer) 1
redis>TTL foo
(integer) -1
除了PERSIST命令之外,使用SET或GETSET命令为键赋值也会同时清除键的生存时间,
例如:
redis>EXPIRE foo 20
(integer) 1
redis>SET foo bar
OK
redis>TTL foo
(integer) -1
其他只对键值进行操作的命令(如INCR、LPUSH、HSET、ZREM)均不会影响键的生存时间。
EXPIRE命令的seconds参数必须是整数,所以最小单位是1秒。如果想要更精确的控制键
的生存时间应该使用PEXPIRE命令,PEXPIRE命令与EXPIRE的唯一区别是前者的时间单位是
毫秒,即PEXPIRE key 1000与EXPIRE key 1等价。对应地可以用PTTL命令以毫秒为单位返回键
的剩余时间。
SORT命令
SORT命令可以对列表类型、集合类型和有序集合类型键进行排序,并且可以完成与关系数据库中的连接查询相类似的任务。
例如:
redis>SORT tag:ruby:posts
1) "2"
2) "6"
3) "12"
4) "26"
在对有序集合类型排序时会忽略元素的分数,只针对元素自身的值进行排序。例如:
redis>ZADD myzset 50 2 40 3 20 1 60 5
(integer) 4
redis>SORT myzset
1) "1"
2) "2"
3) "3"
4) "5"
除了可以排列数字外,SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字
元素,就像这样:
redis>SORT mylistalpha ALPHA
1) "A"
2) "B"
3) "C"
可以看到如果没有加ALPHA参数的话,SORT命令会尝试将所有元素转换成双精度浮点数来比较,如果无法转换则会提示错误。
SORT命令还支持LIMIT参数来返回指定范围的结果。用法和SQL语句一样,LIMIT offset count,表示跳过前offset个元素并获取之后的count个元素。
SORT命令的参数可以组合使用,像这样:
redis>SORT tag:ruby:posts DESC LIMIT 1 2
1) "12"
2) "6"
SORT命令可以对列表类型、集合类型和有序集合类型键进行排序,并且可以完成与关系数据库中的连接查询相类似的任务。
例如:
redis>SORT tag:ruby:posts
1) "2"
2) "6"
3) "12"
4) "26"
在对有序集合类型排序时会忽略元素的分数,只针对元素自身的值进行排序。例如:
redis>ZADD myzset 50 2 40 3 20 1 60 5
(integer) 4
redis>SORT myzset
1) "1"
2) "2"
3) "3"
4) "5"
除了可以排列数字外,SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字
元素,就像这样:
redis>SORT mylistalpha ALPHA
1) "A"
2) "B"
3) "C"
可以看到如果没有加ALPHA参数的话,SORT命令会尝试将所有元素转换成双精度浮点数来比较,如果无法转换则会提示错误。
SORT命令还支持LIMIT参数来返回指定范围的结果。用法和SQL语句一样,LIMIT offset count,表示跳过前offset个元素并获取之后的count个元素。
SORT命令的参数可以组合使用,像这样:
redis>SORT tag:ruby:posts DESC LIMIT 1 2
1) "12"
2) "6"
BY参数
BY 参数的语法为“BY 参考键”。其中参考键可以是字符串类型键或者是散列类型键的某
个字段(表示为键名->字段名)。如果提供了BY参数,SORT命令将不再依据元素自身的值进
行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该
值对元素排序。就像这样:
redis>SORT tag:ruby:posts BY post:* ->time DESC
1) "12"
2) "26"
3) "6"
4) "2"
在上例中SORT命令会读取post:2、post:6、post:12、post:26几个散列键中的time字段的值并
以此决定tag:ruby:posts键中各个文章ID的顺序。
除了散列类型之外,参考键还可以是字符串类型,比如:
redis>LPUSH sortbylist 2
redis>LPUSH sortbylist 1
redis>LPUSH sortbylist 3
(integer) 3
redis>SET itemscore:1 50
OK
redis>SET itemscore:2 100
OK
redis>SET itemscore:3 -10
OK
redis>SORT sortbylist BY itemscore:* DESC
1) "2"
2) "1"
3) "3"
补充知识 参考键虽然支持散列类型,但是“*”只能在“->”符号前面(即键名部分)
才有用,在“->”后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替
換,即常量键名。
BY 参数的语法为“BY 参考键”。其中参考键可以是字符串类型键或者是散列类型键的某
个字段(表示为键名->字段名)。如果提供了BY参数,SORT命令将不再依据元素自身的值进
行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该
值对元素排序。就像这样:
redis>SORT tag:ruby:posts BY post:* ->time DESC
1) "12"
2) "26"
3) "6"
4) "2"
在上例中SORT命令会读取post:2、post:6、post:12、post:26几个散列键中的time字段的值并
以此决定tag:ruby:posts键中各个文章ID的顺序。
除了散列类型之外,参考键还可以是字符串类型,比如:
redis>LPUSH sortbylist 2
redis>LPUSH sortbylist 1
redis>LPUSH sortbylist 3
(integer) 3
redis>SET itemscore:1 50
OK
redis>SET itemscore:2 100
OK
redis>SET itemscore:3 -10
OK
redis>SORT sortbylist BY itemscore:* DESC
1) "2"
2) "1"
3) "3"
补充知识 参考键虽然支持散列类型,但是“*”只能在“->”符号前面(即键名部分)
才有用,在“->”后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替
換,即常量键名。
STORE参数
默认情况下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数。
保存后的键的类型为列表类型,如果键已经存在则会覆盖它。加上STORE参数后SORT命令的返回值为结果的个数。
SORT是Redis中最强大最复杂的命令之一,如果使用不好很容易成为性能瓶颈。SORT命
令的时间复杂度是0(n+mlogm),其中n表示要排序的列表(集合或有序集合)中的元素个数,m
表示要返回的元素个数。当n较大的时候SORT命令的性能相对较低,并且Redis在排序前会建
立一个长度为n① 的容器来存储待排序的元素,虽然是一个临时的过程,但如果同时进行较多
的大数据量排序操作则会严重影响性能。
所以开发中使用SORT命令时需要注意以下几点。
(1)尽可能减少待排序键中元素的数量(使n尽可能小)。
(2)使用LIMIT参数只获取需要的数据(使m尽可能小)。
(3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。
默认情况下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数。
保存后的键的类型为列表类型,如果键已经存在则会覆盖它。加上STORE参数后SORT命令的返回值为结果的个数。
SORT是Redis中最强大最复杂的命令之一,如果使用不好很容易成为性能瓶颈。SORT命
令的时间复杂度是0(n+mlogm),其中n表示要排序的列表(集合或有序集合)中的元素个数,m
表示要返回的元素个数。当n较大的时候SORT命令的性能相对较低,并且Redis在排序前会建
立一个长度为n① 的容器来存储待排序的元素,虽然是一个临时的过程,但如果同时进行较多
的大数据量排序操作则会严重影响性能。
所以开发中使用SORT命令时需要注意以下几点。
(1)尽可能减少待排序键中元素的数量(使n尽可能小)。
(2)使用LIMIT参数只获取需要的数据(使m尽可能小)。
(3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。
“发布/订阅”模式
发布者发布消息的命令是PUBLISH,用法是PUBLISH channel message,如向channel.1说一
声“hi”:
redis>PUBLISH channel.1 hi
(integer) 0
订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel[channel …]。
例如:
redis A>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.1"
3) (integer) 1
除了可以使用SUBSCRIBE命令订阅指定名称的频道外,还可以使用PSUBSCRIBE命令订
阅指定的规则。规则支持glob风格通配符格式(见3.1节),下面我们新打开一个redis-cli实例C
进行演示:
redis C>PSUBSCRIBE channel.?*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel.?*"
3) (integer) 1
规则channel.?*可以匹配channel.1和channel.10,但不会匹配channel.。
PUNSUBSCRIBE命令可以退订指定的规则,用法是PUNSUBSCRIBE [pattern[pattern …]],如果没有参数则会退订所有规则。
注意 使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道;同样UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则。
管道
客户端和Redis使用TCP协议连接。不论是客户端向Redis发送命令还是Redis向客户端返
回命令的执行结果,都需要经过网络传输,这两个部分的总耗时称为往返时延。
Redis的底层通信协议对管道(pipelining)提供了支持。通过管道可以一次性发送多条命令
并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果时
就可以将这组命令一起通过管道发出。管道通过减少客户端与Redis的通信次数来实现降低往
返时延累计值的目的
客户端和Redis使用TCP协议连接。不论是客户端向Redis发送命令还是Redis向客户端返
回命令的执行结果,都需要经过网络传输,这两个部分的总耗时称为往返时延。
Redis的底层通信协议对管道(pipelining)提供了支持。通过管道可以一次性发送多条命令
并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果时
就可以将这组命令一起通过管道发出。管道通过减少客户端与Redis的通信次数来实现降低往
返时延累计值的目的
八、Redis高级应用