python中使用redis
准备
安装redis服务
点击查看Ubuntu中安装Redis。
安装依赖包
pip install redis
使用
import redis
创建连接
1、普通连接:
conn = redis.Redis(host='127.0.0.1',port=6379,password='1234')
2、连接池:
conn_pool = redis.ConnectionPool(host='127.0.0.1',port=6379,password='1234') conn = redis.Redis(connection_pool=conn_pool)
String(字符串)操作
Redis 中的 String 在在内存中按照一个 name 对应一个 value 来存储。
-
set
conn.set(name, value, ex=None, px=None, nx=False, xx=False)
可选参数:
ex :设置键的过期时间为 second 秒。
px :设置键的过期时间为 millisecond 毫秒。
nx :只在键不存在时,才对键进行设置操作。
xx :只在键已经存在时,才对键进行设置操作。
返回值:
在 Redis 2.6.12 版本以前, set 命令总是返回 True 。
从 Redis 2.6.12 版本开始, set 在设置操作成功完成时,才返回 True 。
如果设置了 nx 或者 xx ,但因为条件没达到而造成设置操作未执行,那么命令返回 None 。 -
setnx
conn.setnx(name, value)
返回值: 设置成功,返回 True 。 设置失败,返回 False 。
-
setex
conn.setex(name, time, value)
conn.set(name,value) conn.expire(name,time)
返回值: 设置成功时返回 OK 。 当 time 参数不合法时,返回一个错误。
-
psetex
conn.psetex(name, time_ms, value)
返回值: 设置成功时返回 OK 。
-
mset
conn.mset(mapping) 例: conn.mset(k1='v1', k2='v2') conn.mset({'k1': 'v1', 'k2': 'v2'})
同时设置一个或多个 key-value 对。
如果某个给定 key 已经存在,那么 mset 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 msetnx 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
mset 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
返回值: 总是返回 True (因为 mset 不可能失败)。
-
msetnx
conn.msetnx(mapping)
同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
即使只有一个给定 key 已存在, msetnx 也会拒绝执行所有给定 key 的设置操作。
msetnx 是原子性的,因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object),所有字段要么全被设置,要么全不被设置。
返回值: 当所有 key 都成功设置,返回 True 。 如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 False 。
-
get
conn.get(name)
如果 name 不存在那么返回特殊值 None 。
假如 name 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。
返回值: 当 name 不存在时,返回 None ,否则,返回 name 的值。 如果 name 不是字符串类型,那么返回一个错误。
-
mget
conn.mget(keys, *args) 例: value_list = conn.mget('k1','k2') 或 value_list = conn.mget(['k1','k2']) # [b'v1', b'v2']
如果给定的 name 里面,有某个 name 不存在,那么这个 name 返回特殊值 None 。因此,该命令永不失败。
返回值: 一个包含所有给定 name 的值的列表。
-
getset
conn.getset(name,value)
将给定 name 的值设为 value ,并返回 name 的旧值(old value)。
当 name 存在但不是字符串类型时,返回一个错误。返回值: 返回给定 name 的旧值。 当 name 没有旧值时,也即是, name 不存在时,返回 None 。
-
getrange
conn.getrange(key, start, end) 例: conn.set('str', 'helloworld') print(conn.getrange('str', 0, 3)) # b'hell'
返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。返回值: 截取得出的子字符串。
-
setrange
conn.setrange(name, offset, value) 例: conn.set('str1', 'hello') conn.set('str2', 'hello') conn.setrange('str1', 5, ' zze') print(conn.get('str1')) # b'hello zze' conn.setrange('str2', 6, 'world') print(conn.get('str2')) # b'hello\x00world'
不存在的 name 当作空白字符串处理。
setrange 命令会确保字符串足够长以便将 value 设置在指定的偏移量上,如果给定 name 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ),那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )来填充。
注意你能使用的最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间,你可以使用多个 key 。
返回值: 被 setrange 修改之后,字符串的长度。
-
setbit
conn.setbit(name, offset, value)
例:
注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:01100110 01101111 01101111
所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
那么最终二进制则变成 01100111 01101111 01101111,即:"goo"对name对应值的二进制表示的位进行操作。
对 name 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。
当 name 不存在时,自动生成一个新的字符串值。
字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。
offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
返回值: 指定偏移量原来储存的位。
-
getbit
conn.getbit(name, offset)
获取name对应的值的二进制表示中的某位的值(0或1)。
对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。
返回值: 字符串值指定偏移量上的位(bit)。
-
bitcount
conn.bitcount(key, start=None, end=None)
计算给定字符串中,被设置为 1 的比特位的数量。
一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
start 和 end 参数的设置和 getrange 命令类似,都可以使用负数值: 比如 -1 表示最后一个字节, -2 表示倒数第二个字节,以此类推。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 bitcount 操作,结果为 0 。
返回值: 被设置为 1 的位的数量。
Bitmap 对于一些特定类型的计算非常有效。 假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT 和 BITCOUNT 来实现。 比如说,每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。 举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。 当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。
-
strlen
conn.strlen(name)
返回 name 所储存的字符串值的长度。
当 name 储存的不是字符串值时,返回一个错误。
返回值: 字符串值的长度。 当 name 不存在时,返回 0 。
-
incr
conn.incr(self, name, amount=1)
将 name 中储存的数字值增 amount。
如果 name 不存在,那么 name 的值会先被初始化为 0 ,然后再执行 incr 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
返回值: 执行 incr 命令之后 name 的值。
-
incrbyfloat
conn.incrbyfloat(self, name, amount=1.0)
为 name 中所储存的值加上浮点数增量 amount 。
如果 name 不存在,那么 incrbyfloat 会先将 key 的值设为 0 ,再执行加法操作。
如果命令执行成功,那么 name 的值会被更新为(执行加法之后的)新值,并且新值会以字符串的形式返回给调用者。
无论是 name 的值,还是增量 amount ,都可以使用像 2.0e7 、 3e5 、 90e-2 那样的指数符号(exponential notation)来表示,但是,执行 incrbyfloat 命令之后的值总是以同样的形式储存,也即是,它们总是由一个数字,一个(可选的)小数点和一个任意位的小数部分组成(比如 3.14 、 69.768 ,诸如此类),小数部分尾随的 0 会被移除,如果有需要的话,还会将浮点数改为整数(比如 3.0 会被保存成 3 )。
除此之外,无论加法计算所得的浮点数的实际精度有多长, incrbyfloat 的计算结果也最多只能表示小数点的后十七位。
当以下任意一个条件发生时,返回一个错误:
- name 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
- name 当前的值或者给定的增量 amount 不能解释(parse)为双精度浮点数(double precision floating point number)
返回值: 执行命令之后 key 的值。
-
decr
conn.decr(self, name, amount=1)
将 name 中储存的数字值减 amount 。
如果 name 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 decr 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
返回值: 执行 DECR 命令之后 key 的值。
-
append
conn.ppend(key, value)
如果 key 已经存在并且是一个字符串, append 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, append 就简单地将给定 key 设为 value 。
返回值: 追加 value 之后, key 中字符串的长度。
Hash(哈希)操作
hash 表现形式上有些像 pyhton 中的 字典 ,可以存储一组关联性较强的数据。
-
hset
conn.hset(name, key, value)
将 name 对应的 hash 域 中 key 值设为 value 。
如果 name 不存在,一个新的哈希表将被创建并进行 hset 操作。如果域 key 已经存在于哈希表中,旧值将被覆盖。
返回值: 如果 key 是哈希表中的一个新建域,并且值设置成功,返回 True 。 如果哈希表中域 key 已经存在且旧值已被新值覆盖,返回 False 。
-
hmset
conn.hmset(name, mapping) 例: conn.hmset('xx', {'k1':'v1', 'k2': 'v2'})
同时将多个 key-value (键-值)对设置到哈希表 name 中。
此命令会覆盖哈希表中已存在的域。
如果 name 不存在,一个空哈希表被创建并执行 hmset 操作。
返回值: 如果命令执行成功,返回 True 。 当 key 不是哈希表(hash)类型时,返回一个错误。
-
hget
conn.hget(name,key)
返回哈希表 name 中给定域 key 的值。
返回值: 给定域的值。 当给定域不存在或是给定 name 不存在时,返回 None 。
-
hmget
conn.hmget(name, keys, *args) 例: r.mget('xx', ['k1', 'k2']) 或 r.hmget('xx', 'k1', 'k2')
返回哈希表 name 中,一个或多个给定域的值。
如果给定的域不存在于哈希表,那么返回一个 None 。
因为不存在的 name 被当作一个空哈希表来处理,所以对一个不存在的 name 进行 hmget 操作将返回一个只带有 None 值的表。
返回值: 一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。
-
hgetall
conn.hgetall(name)
返回哈希表 name 中,所有的域和值。
返回值: 以字典形式返回哈希表的域和域的值。 若 name 不存在,返回空字典。
-
hlen
conn.hlen(name)
返回哈希表 name 中域的数量。
返回值: 哈希表中域的数量。 当 name 不存在时,返回 0 。
-
hkeys
conn.hkeys(name)
返回哈希表 key 中的所有域。
返回值: 一个包含哈希表中所有域的列表。 当 key 不存在时,返回一个空列表。
-
hvals
conn.hvals(name)
返回哈希表 name 中所有域的值。
返回值: 一个包含哈希表中所有值的列表。 当 name 不存在时,返回一个空列表表。
-
hexists
conn.hexists(name, key)
查看哈希表 name 中,给定域 key 是否存在。
返回值: 如果哈希表含有给定域,返回 1 。 如果哈希表不含有给定域,或 name 不存在,返回 0 。
-
hdel
conn.hdel(name,*keys)
删除哈希表 name 中的一个或多个指定域,不存在的域将被忽略。
返回值: 被成功移除的域的数量,不包括被忽略的域。
-
hincrby
conn.hincrby(name, key, amount=1)
为哈希表 name 中的域 key 的值加上增量 amount 。
增量也可以为负数,相当于对给定域进行减法操作。
如果 name 不存在,一个新的哈希表被创建并执行 hincrby 命令。
如果域 key 不存在,那么在执行命令前,域的值被初始化为 0 。
对一个储存字符串值的域 key 执行 hincrby 命令将造成一个错误。
本操作的值被限制在 64 位(bit)有符号数字表示之内。
返回值: 执行 hincrby 命令之后,哈希表 name 中域 key 的值。
-
hincrbyfloat
conn.hincrbyfloat(name, key, amount=1.0)
为哈希表 name 中的域 key 加上浮点数增量 amount 。
如果哈希表中没有域 key ,那么 hincrbyfloat 会先将域 key 的值设为 0 ,然后再执行加法操作。
如果键 name 不存在,那么 hincrbyfloat 会先创建一个哈希表,再创建域 key ,最后再执行加法操作。
当以下任意一个条件发生时,返回一个错误:
- 域 key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
- 域 key 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)
-
hscan
conn.hscan(name, cursor=0, match=None, count=None)
增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆。
可选参数: cursor :游标(基于游标分批取获取数据)。 match :匹配指定 key ,默认 None 表示所有的 key 。 count :每次分片最少获取个数,默认 None 表示采用 Redis 的默认分片个数
返回值:
返回一个包含两个元素的元组,第一个元素是一个数字(测试时一直返回 0 ,不知道是什么意思),第二个元素为域和值作为键值对的一个字典。 -
hscan_iter
conn.hscan_iter(name, match=None, count=None)
利用 yield 封装 hscan 创建生成器,实现分批去 redis 中获取数据。
参数和返回值参考 hscan 。
-
hsetnx
conn.hsetnx(name, key, value)
将哈希表 name 中的域 key 的值设置为 value ,当且仅当域 key 不存在。
若域 key 已经存在,该操作无效。
如果 name 不存在,一个新哈希表被创建并执行 hsetnx 命令。
返回值: 设置成功,返回 1 。 如果给定域已经存在且没有操作被执行,返回 0 。
-
hstrlen
conn.hstrlen(name, key):
返回哈希表 name 中, 与给定域 key 相关联的值的字符串长度(string length)。
如果给定的键或者域不存在, 那么命令返回 False 。
返回值: 一个整数。
List(列表)操作
redis 中的 List 在内存中按照一个 name 对应一个列表来存储。
-
lpush
conn.lpush(name, *values) 例: 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头。 比如说,对空列表 mylist 执行命令 lpush('mylist','a','b','c') , 列表的值将是 'c','b','a',这等同于原子性地执行 lpush('mylist','a') 、 lpush('mylist','b') 和 lpush('mylist','c') 三个命令。
将一个或多个值 value 插入到列表 name 的表头。
如果 name 不存在,一个空列表会被创建并执行 LPUSH 操作。
当 name存在但不是列表类型时,返回一个错误。
返回值: 执行 lpush 命令后,列表的长度。
-
rpush
conn.rpush(name, *values): 例: 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 rpush('mylist','a','b','c'), 得出的结果列表为 'a','b','c' ,等同于执行命令 rpush('mylist','a')、rpush('mylist','b') 和 rpush('mylist','c') 。
将一个或多个值 value 插入到列表 key 的表尾(最右边)。
如果 name 不存在,一个空列表会被创建并执行 rpush 操作。
当 name 存在但不是列表类型时,返回一个错误。
返回值: 执行 rpush 操作后,表的长度。
-
lpushx
conn.lpushx(name, value)
将值 value 插入到列表 name 的表头,当且仅当 name 存在并且是一个列表。
和 lpush 命令相反,当 name 不存在时, lpushx 命令什么也不做。
返回值: lpushx 命令执行之后,表的长度。
-
rpushx
conn.rpushx(name, value):
将值 value 插入到列表 name 的表尾,当且仅当 name 存在并且是一个列表。
和 rpush 命令相反,当 name 不存在时, rpushx 命令什么也不做。
返回值: rpushx 命令执行之后,表的长度。
-
llen
conn.llen(name):
返回列表 name 的长度。
如果 name 不存在,则 name 被解释为一个空列表,返回 0 。
如果 name 不是列表类型,返回一个错误。
返回值: 列表 key 的长度。
-
linsert
conn.linsert(name, where, refvalue, value):
将值 value 插入到列表 name 当中,位于值 refvalue 之前或之后。
当 refvalue 不存在于列表 name 时,不执行任何操作。
当 name 不存在时, name 被视为空列表,不执行任何操作。
如果 name 不是列表类型,返回一个错误。
参数: where :BEFORE或AFTER。 refvalue :标杆值,即:在它前后插入数据。 value :要插入的数据。 返回值: 如果命令执行成功,返回插入操作完成之后,列表的长度。 如果没有找到 refvalue ,返回 -1 。 如果 key 不存在或为空列表,返回 0 。
-
lset
conn.lset(name, index, value):
将列表 name 下标为 index 的元素的值设置为 value 。
当 index 参数超出范围,或对一个空列表( name 不存在)进行 lset 时,返回一个错误。
返回值: 操作成功返回 True ,否则返回错误信息。
-
lrem
conn.lrem(name, count, value)
根据参数 count 的值,移除列表中与参数 value 相等的元素。
count 的值可以是以下几种:
- count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
- count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
- count = 0 : 移除表中所有与 value 相等的值。
返回值: 被移除元素的数量。 因为不存在的 name 被视作空表(empty list),所以当 name 不存在时, lrem 命令总是返回 0 。
-
lpop
conn.lpop(name):
移除并返回列表 name 的头元素。
返回值: 列表的头元素。 当 name 不存在时,返回 None 。
-
lindex
conn.lindex(name, index)
返回列表 name 中,下标为 index 的元素。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
如果 key 不是列表类型,返回一个错误。
返回值: 列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range),返回 None 。
-
lrange
conn.lrange(name, start, end)
返回列表 name 中指定区间内的元素,区间以偏移量 start 和 end 指定。
下标(index)参数 start 和 end 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
超出范围的下标: 超出范围的下标值不会引起错误。 如果 start 下标比列表的最大下标( llen('list')-1 )还要大,那么 lrange 返回一个空列表。 如果 end 下标比最大下标还要大,Redis将最大下标的值设置为 end 。 返回值: 一个列表,包含指定区间内的元素。
-
ltrim
conn.ltrim(name, start, end)
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
举个例子,执行命令 ltrim('list',0,2) ,表示只保留列表 list 的前三个元素,其余元素全部删除。
下标(index)参数 start 和 end 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
当 key 不是列表类型时,返回一个错误。
超出范围的下标: 超出范围的下标值不会引起错误。 如果 start 下标比列表的最大下标( llen('list')-1 )还要大,或者 start > end , ltrim 返回一个空列表(因为 ltrim 已经将整个列表清空)。 如果 end 下标比最大下标还要大,Redis将最大下标的值设置为 end 。 返回值: 命令执行成功时,返回 True 。
-
rpoplpush
conn.rpoplpush(src, dst)
命令 rpoplpush 在一个原子时间内,执行以下两个动作:
- 将列表 src 中的最后一个元素(尾元素)弹出,并返回给客户端。
- 将 src 弹出的元素插入到列表 dst ,作为 dst 列表的的头元素。
举个例子,你有两个列表 src 和 dst , src 列表有元素 'a','b','c' , destination 列表有元素 'x','y','z' ,执行 rpoplpush('src','dst') 之后, src 列表包含元素 'a','b' , destination 列表包含元素 'c','x','y','z' ,并且元素 'c' 会被返回给客户端。
如果 src 不存在,值 None 被返回,并且不执行其他动作。
如果 src 和 dst 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。
返回值: 被弹出的元素。
-
blpop
conn.blpop(keys, timeout=0)
blpop 是列表的阻塞式(blocking)弹出。
它是 lpop 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 blpop 命令阻塞,直到等待超时或发现可弹出元素为止。
当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
非阻塞行为: 当 blpop 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者。 当存在多个给定 key 时, blpop 按给定 key 参数排列的先后顺序,依次检查各个列表。 阻塞行为: 如果所有给定 key 都不存在或包含空列表,那么 blpop 命令将阻塞连接,直到等待超时,或有另一个客户端对给定 key 的任意一个执行 lpush 或 rpush 命令为止。 超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。 相同的key被多个客户端同时阻塞: 相同的 key 可以被多个客户端同时阻塞。 不同的客户端被放进一个队列中,按『先阻塞先服务』(first-BLPOP,first-served)的顺序为 key 执行 blpop 命令。 在MULTI/EXEC事务中的blpop: blpop 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在 MULTI / EXEC 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 lpush 或 rpush 命令。 因此,一个被包裹在 MULTI / EXEC 块内的 blpop 命令,行为表现得就像 lpop 一样,对空列表返回 None ,对非空列表弹出列表元素,不进行任何阻塞操作。 返回值: 如果列表为空,返回一个 None 。 否则,返回一个含有两个元素的元组,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
-
brpoplpush
conn.brpoplpush(src, dst, timeout=0):
brpoplpush 是 brpoplpush 的阻塞版本,当给定列表 source 不为空时, brpoplpush 的表现和 brpoplpush 一样。
当列表 src 为空时, brpoplpush 命令将阻塞连接,直到等待超时,或有另一个客户端对 src 执行 lpush 或 rpush 命令为止。
超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。
返回值: 假如在指定时间内没有任何元素被弹出,则返回一个 None 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。
Set(集合)操作
Set操作,Set集合就是不允许重复的列表。
-
sadd
conn.sadd(name, *values):
将一个或多个 value 元素加入到集合 name 当中,已经存在于集合的 value 元素将被忽略。
假如 name 不存在,则创建一个只包含 value 元素作成员的集合。
当 name 不是集合类型时,返回一个错误。
返回值: 被添加到集合中的新元素的数量,不包括被忽略的元素。
-
scard
conn.scard(name)
返回集合 key 的基数(集合中元素的数量)。
返回值: 集合的基数。 当 key 不存在时,返回 0 。
-
sdiff
conn.sdiff(keys, *args)
返回一个集合的全部成员,该集合是所有给定集合之间的差集。
不存在的 key 被视为空集。
返回值: 一个包含差集成员的列表。
-
sdiffstore
conn.sdiffstore(dest, keys, *args)
这个命令的作用和 sdiff 类似,但它将结果保存到 dest 集合,而不是简单地返回结果集。
如果 dest 集合已经存在,则将其覆盖。dest 可以是 key 本身。
返回值: 结果集中的元素数量。
-
sinter
conn.sinter(keys, *args)
返回一个集合的全部成员,该集合是所有给定集合的交集。
不存在的 key 被视为空集。
当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。
返回值: 交集成员的列表。
-
sinterstore
conn.sinterstore(dest, keys, *args)
这个命令类似于 sinter 命令,但它将结果保存到 dest 集合,而不是简单地返回结果集。
如果 dest 集合已经存在,则将其覆盖。
dest 可以是 key 本身。
返回值: 结果集中的成员数量。
-
sismember
conn.sismember(name, value)
判断 value 元素是否集合 name 的成员。
返回值: 如果 value 元素是集合的成员,返回 1 。 如果 value 元素不是集合的成员,或 name 不存在,返回 0 。
-
smembers
conn.smembers(name)
返回集合 name 中的所有成员。
不存在的 name 被视为空集合。
返回值: 集合中的所有成员。
-
smove
conn.smove(src, dst, value)
将 value 元素从 src 集合移动到 dst 集合。
smove 是原子性操作。
如果 src 集合不存在或不包含指定的 value 元素,则 smove 命令不执行任何操作,仅返回 0 。否则, value 元素从 src 集合中被移除,并添加到 dst 集合中去。
当 dst 集合已经包含 value 元素时, smove 命令只是简单地将 src 集合中的 value 元素删除。
当 src 或 dst 不是集合类型时,返回一个错误。
返回值: 如果 value 元素被成功移除,返回 1 。 如果 value 元素不是 src 集合的成员,并且没有任何操作对 dst 集合执行,那么返回 0 。
-
spop
conn.spop(name, count=None)
移除并返回集合中的一个随机元素。
如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 srandmember 命令。
返回值: 被移除的随机元素。 当 name 不存在或 name 是空集时,返回 None 。
-
srandmember
conn.srandmember(name, number=None)
如果命令执行时,只提供了 name 参数,那么返回集合中的一个随机元素。
从 Redis 2.6 版本开始, srandmember 命令接受可选的 number 参数:
- 如果 number 为正数,且小于集合基数,那么命令返回一个包含 number 个元素的数组,数组中的元素各不相同。如果 number 大于等于集合基数,那么返回整个集合。
- 如果 number 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 number 的绝对值。
该操作和 spop 相似,但 spop 将随机元素从集合中移除并返回,而 srandmember 则仅仅返回随机元素,而不对集合进行任何改动。
返回值: 只提供 name 参数时,返回一个元素;如果集合为空,返回 None 。 如果提供了 number 参数,那么返回一个数组;如果集合为空,返回空数组。
-
srem
conn.srem(name, *values)
移除集合 name 中的一个或多个 value 元素,不存在的 value 元素会被忽略。
当 name 不是集合类型,返回一个错误。
返回值: 被成功移除的元素的数量,不包括被忽略的元素。
-
sunion
conn.sunion(keys, *args)
返回一个集合的全部成员,该集合是所有给定集合的并集。
不存在的 key 被视为空集。
返回值: 并集成员的列表。
-
sunionstore
conn.sunionstore(dest, keys, *args)
这个命令类似于 sunion 命令,但它将结果保存到 dest 集合,而不是简单地返回结果集。
如果 dest 已经存在,则将其覆盖。
dest 可以是 key 本身。
返回值: 结果集中的元素数量。
-
sscan
conn.sscan(name, cursor=0, match=None, count=None)
用于迭代集合键中的元素。
返回值: 返回的每个元素都是一个集合成员。
-
sscan_iter
sscan_iter(name, match=None, count=None)
利用 yield 封装 hscan 创建生成器,实现分批去 redis 中获取数据。
返回值参考 sscan 。
SortSet(有序集合)操作
在集合的基础上,为元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
-
zadd
conn.zadd(name, mapping, nx=False, xx=False, ch=False, incr=False)
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
score 值可以是整数值或双精度浮点数。
如果 key 不存在,则创建一个空的有序集并执行 zadd 操作。
当 key 存在但不是有序集类型时,返回一个错误。
返回值: 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
-
zcard
conn.zcard(name)
返回有序集 name 的基数。
返回值: 当 name 存在且是有序集类型时,返回有序集的基数。 当 name 不存在时,返回 0 。
-
zcount
conn.zcount(name, min, max)
返回有序集 name 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
返回值: score 值在 min 和 max 之间的成员的数量。
-
zincrby
conn.zincrby(name, amount, value)
为有序集 name 的成员 value 的 score 值加上增量 amount 。
可以通过传递一个负数值 amount ,让 score 减去相应的值,比如 zincrby(name, -5, value) ,就是让 value 的 score 值减去 5 。
当 name 不存在,或 value 不是 name 的成员时, zincrby(name, amount, value) 等同于 conn.zadd(name,{value:amount}) 。
当 name 不是有序集类型时,返回一个错误。
amount 值可以是整数值或双精度浮点数。
返回值: value 成员的新 score 值,以字符串形式表示。
-
zrange
conn.zrange(name, start, end, desc=False, withscores=False, score_cast_func=float)
返回有序集 name 中,指定区间内的成员。
其中成员的位置默认按 score 值递增(从小到大)来排序,通过 desc 参数就可以让其反序。
具有相同 score 值的成员按字典序(lexicographical order )来排列。
下标参数 start 和 end 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
超出范围的下标并不会引起错误。比如说,当 start 的值比有序集的最大下标还要大,或是 start > end 时, zrange 命令只是简单地返回一个空列表。
另一方面,假如 end 参数的值比有序集的最大下标还要大,那么 Redis 将 end 当作最大下标来处理。
可以通过使用 withscores 选项,来让成员和它的 score 值一并返回,返回一个填充元组的列表,元组的第一个元素是对应值,第二个元素是元素 score。
可以通过参数 score_cast_func 指定返回的 score 的表现形式,默认是 float ,表示为小数。
返回值: 指定区间内,带有 score 值(可选)的有序集成员的列表。
-
zrank
conn.zrank(name, value)
返回有序集 name 中成员 value 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
排名以 0 为底,也就是说, score 值最小的成员排名为 0 。
返回值: 如果 value 是有序集 name 的成员,返回 value 的排名。 如果 value 不是有序集 name 的成员,返回 None 。
-
zrem
conn.zrem(name, *values)
移除有序集 name 中的一个或多个成员,不存在的成员将被忽略。
当 name 存在但不是有序集类型时,返回一个错误。
返回值: 被成功移除的成员的数量,不包括被忽略的成员。
-
zremrangebyrank
conn.zremrangebyrank(name, min, max)
移除有序集 name 中,指定排名(rank)区间内的所有成员。
区间分别以下标参数 min 和 max 指出,包含 min 和 max 在内。
下标参数 min 和 max 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
返回值: 被移除成员的数量。
-
zremrangebyscore
conn.zremrangebyscore(name, min, max)
移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。
自版本2.1.6开始, score 值等于 min 或 max 的成员也可以不包括在内。
返回值: 被移除成员的数量。
-
zscore
conn.zscore(name, value)
返回有序集 name 中,成员 value 的 score 值。
如果 value 元素不是有序集 key 的成员,或 key 不存在,返回 None 。
返回值: value 成员的 score 值,以字符串形式表示。
-
zinterstore
conn.zinterstore(dest, keys, aggregate=None)
计算给定的一个或多个有序集的交集,并将该交集(结果集)储存到 dest 。
默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之和。
返回值: 保存到 dest 的结果集的基数。
-
zunionstore
conn.zunionstore(dest, keys, aggregate=None)
计算给定的一个或多个有序集的并集,并将该并集(结果集)储存到 dest 。
默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之和 。
aggregate 使用 aggregate 选项,你可以指定并集的结果集的聚合方式。 默认使用的参数 SUM ,可以将所有集合中某个成员的 score 值之 和 作为结果集中该成员的 score 值;使用参数 MIN ,可以将所有集合中某个成员的 最小 score 值作为结果集中该成员的 score 值;而参数 MAX 则是将所有集合中某个成员的 最大 score 值作为结果集中该成员的 score 值。 返回值: 保存到 dest 的结果集的基数。
-
zscan
conn.zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
返回值: 返回的每个元素都是一个集合成员。
-
zsacniter
conn.zscan_iter(name, match=None, count=None, score_cast_func=float)
利用 yield 封装 zscan 创建生成器,实现分批去 redis 中获取数据。
返回值参考 zscan 。
Key(键)操作
-
delete
conn.delete(*names)
删除给定的一个或多个 key 。
不存在的 key 会被忽略。
返回值: 被删除 name 的数量。
-
dump
conn.dump(name)
序列化给定 name ,并返回被序列化的值,使用 restore 命令可以将这个值反序列化为 Redis 键。
序列化生成的值有以下几个特点:
- 它带有 64 位的校验和,用于检测错误, restore 在进行反序列化之前会先检查校验和。
- 值的编码格式和 RDB 文件保持一致。
- RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本不同造成 RDB 格式不兼容,那么 Redis 会拒绝对这个值进行反序列化操作。
序列化的值不包括任何生存时间信息。
返回值: 如果 key 不存在,那么返回 None 。 否则,返回序列化之后的值。
-
exists
conn.exists(*names)
检查给定 key 是否存在。
返回值: 存在 key 的数量 ,没有则返回 0 。
-
expire
conn.expire(name, time)
为给定 name 设置生存时间,当 name 过期时(生存时间为 0 ),它会被自动删除。
在 Redis 中,带有生存时间的 name 被称为『易失的』(volatile)。
生存时间可以通过使用 delete 命令来删除整个 name 来移除,或者被 set 和 getset 命令覆写(overwrite),这意味着,如果一个命令只是修改(alter)一个带生存时间的 name 的值而不是用一个新的 name 值来代替(replace)它的话,那么生存时间不会被改变。
比如说,对一个 name 执行 incr 命令,对一个列表进行 lpush 命令,或者对一个哈希表执行 hset 命令,这类操作都不会修改 key 本身的生存时间。
另一方面,如果使用 rename 对一个 name 进行改名,那么改名后的 name 的生存时间和改名前一样。
rename 命令的另一种可能是,尝试将一个带生存时间的 name 改名成另一个带生存时间的 another_name ,这时旧的 another_name (以及它的生存时间)会被删除,然后旧的 name 会改名为 another_name ,因此,新的 another_name 的生存时间也和原本的 name 一样。
使用 persist 命令可以在不删除 name 的情况下,移除 name 的生存时间,让 name 重新成为一个『持久的』(persistent) name 。
更新生存时间: 可以对一个已经带有生存时间的 name 执行 expire 命令,新指定的生存时间会取代旧的生存时间。 过期时间的精确度: 在 Redis 2.4 版本中,过期时间的延迟在 1 秒钟之内 —— 也即是,就算 name 已经过期,但它还是可能在过期之后一秒钟之内被访问到,而在新的 Redis 2.6 版本中,延迟被降低到 1 毫秒之内。 Redis 2.1.3 之前的不同之处: 在 Redis 2.1.3 之前的版本中,修改一个带有生存时间的 name 会导致整个 name 被删除,这一行为是受当时复制(replication)层的限制而作出的,现在这一限制已经被修复。 返回值: 设置成功返回 1 。 当 name 不存在或者不能为 name 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。
-
expireat
conn.expireat(name, when)
expireat 的作用和 expire 类似,都用于为 key 设置生存时间。
不同在于 expireat 命令接受的时间参数是时间戳(timestamp)。
返回值: 如果生存时间设置成功,返回 1 。 当 key 不存在或没办法设置生存时间,返回 0 。
-
keys
conn.keys(pattern='*')
查找所有符合给定模式 pattern 的 key 。
keys('*') 匹配数据库中所有 key 。
keys('h?llo') 匹配 hello , hallo 和 hxllo 等。
keys('h*llo') 匹配 hllo 和 heeeeello 等。
keys('h[ae]llo') 匹配 hello 和 hallo ,但不匹配 hillo 。
特殊符号用 \ 隔开。
返回值: 符合给定模式的 key 列表。
-
migrate
conn.migrate(self, host, port, keys, destination_db, timeout, copy=False, replace=False, auth=None)
将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除。
这个命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等待超时。
命令的内部实现是这样的:它在当前实例对给定 key 执行 dump 命令 ,将它序列化,然后传送到目标实例,目标实例再使用 restore 对数据进行反序列化,并将反序列化所得的数据添加到数据库中;当前实例就像目标实例的客户端那样,只要看到 restore 命令返回 OK ,它就会调用 delete 删除自己数据库上的 key 。
timeout 参数以毫秒为格式,指定当前实例和目标实例进行沟通的最大间隔时间。这说明操作并不一定要在 timeout 毫秒内完成,只是说数据传送的时间不能超过这个 timeout 数。
migrate 命令需要在给定的时间规定内完成 IO 操作。如果在传送数据时发生 IO 错误,或者达到了超时时间,那么命令会停止执行,并返回一个特殊的错误: IOERR 。
当 IOERR 出现时,有以下两种可能:
- key 可能存在于两个实例。
- key 可能只存在于当前实例。
唯一不可能发生的情况就是丢失 key ,因此,如果一个客户端执行 migrate 命令,并且不幸遇上 IOERR 错误,那么这个客户端唯一要做的就是检查自己数据库上的 key 是否已经被正确地删除。
如果有其他错误发生,那么 migrate 保证 key 只会出现在当前实例中。(当然,目标实例的给定数据库上可能有和 key 同名的键,不过这和 migrate 命令没有关系)。
可选项: copy :不移除源实例上的 key 。 replace :替换目标实例上已存在的 key 。 返回值: 迁移成功时返回 True ,否则返回相应的错误。
-
move
move(name, db)
将当前数据库的 name 移动到给定的数据库 db 当中。
如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 name ,或者 name 不存在于当前数据库,那么 move 没有任何效果。
因此,也可以利用这一特性,将 move 当作锁(locking)原语(primitive)。
返回值: 移动成功返回 1 ,失败则返回 0 。
-
persist
conn.persist(name)
移除给定 name 的生存时间,将这个 name 从『易失的』(带生存时间 name )转换成『持久的』(一个不带生存时间、永不过期的 name )。
返回值: 当生存时间移除成功时,返回 1 。 如果 key 不存在或 key 没有设置生存时间,返回 0 。
-
pexpire
conn.pexpire(name, time)
这个命令和 expire 命令的作用类似,但是它以毫秒为单位设置 name 的生存时间,而不像 expire 命令那样,以秒为单位。
返回值: 设置成功,返回 1。 key 不存在或设置失败,返回 0 。
-
pexpireat
conn.pexpireat(name, when)
这个命令和 expireat 命令类似,但它以毫秒为单位设置 name 的过期时间戳,而不是像 expireat 那样,以秒为单位。
返回值: 如果生存时间设置成功,返回 1 。 当 name 不存在或没办法设置生存时间时,返回 0 。(查看 expire 命令获取更多信息)
-
pttl
conn.pttl(name)
这个命令类似于 ttl 命令,但它以毫秒为单位返回 name 的剩余生存时间,而不是像 ttl 命令那样,以秒为单位。
返回值: 当 name 不存在时,返回 -2 。 当 name 存在但没有设置剩余生存时间时,返回 -1 。 否则,以毫秒为单位,返回 name 的剩余生存时间。
-
randomkey
conn.randomkey()
从当前数据库中随机返回(不删除)一个 key 。
返回值: 当数据库不为空时,返回一个 key 。 当数据库为空时,返回 None 。
-
rename
conn.rename(src, dst)
将 src 改名为 dst 。
当 src 和 dst 相同,或者 src 不存在时,返回一个错误。
当 dest 已经存在时, rename 命令将覆盖旧值。
返回值: 改名成功时提示 True ,失败时候返回一个错误。
-
renamenx
conn.renamenx(src, dst)
当且仅当 dst 不存在时,将 src 改名为 dst 。
当 src 不存在时,返回一个错误。
返回值: 修改成功时,返回 1 。 如果 dst 已经存在,返回 0 。
-
restore
conn.restore(name, ttl, value, replace=False)
反序列化给定的序列化值,并将它和给定的 name 关联。
参数 ttl 以毫秒为单位为 name 设置生存时间;如果 ttl 为 0 ,那么不设置生存时间。
restore 在执行反序列化之前会先对序列化值的 RDB 版本和数据校验和进行检查,如果 RDB 版本不相同或者数据不完整的话,那么 restore 会拒绝进行反序列化,并返回一个错误。
如果键 name 已经存在, 并且给定了 replace 选项, 那么使用反序列化得出的值来代替键 name 原有的值; 相反地, 如果键 name 已经存在, 但是没有给定 replace 选项, 那么命令返回一个错误。
返回值: 如果反序列化成功那么返回 True ,否则返回一个错误。
-
sort
conn.sort(name, start=None, num=None, by=None, get=None, desc=False, alpha=False, store=None, groups=False)
返回或保存给定列表、集合、有序集合 key 中经过排序的元素。
排序默认以数字作为对象,值被解释为双精度浮点数,然后进行比较。
返回值: 没有使用 store 参数,返回列表形式的排序结果。 使用 store 参数,返回排序结果的元素数量。
-
ttl
conn.ttl(name)
以秒为单位,返回给定 name 的剩余生存时间(TTL, time to live)。
返回值: 当 name 不存在时,返回 -2 。 当 name 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 name 的剩余生存时间。
-
type
conn.type(name)
返回 key 所储存的值的类型。
返回值: none (key不存在) string (字符串) list (列表) set (集合) zset (有序集) hash (哈希表)
-
scan
conn.scan(cursor=0, match=None, count=None)
scan 命令及其相关的 sscan 命令、 hscan 命令和 zscan 命令都用于增量地迭代(incrementally iterate)一集元素(a collection of elements):
- scan 命令用于迭代当前数据库中的数据库键。
- sscan 命令用于迭代集合键中的元素。
- hscan 命令用于迭代哈希键中的键值对。
- zscan 命令用于迭代有序集合中的元素(包括元素成员和元素分值)。
以上列出的四个命令都支持增量式迭代, 它们每次执行都只会返回少量元素, 所以这些命令可以用于生产环境, 而不会出现像 key 命令、 smembers 命令带来的问题 —— 当 keys 命令被用于处理一个大的数据库时, 又或者 smembers 命令被用于处理一个大的集合键时, 它们可能会阻塞服务器达数秒之久。
不过, 增量式迭代命令也不是没有缺点的: 举个例子, 使用 smembers 命令可以返回集合键当前包含的所有元素, 但是对于 scan 这类增量式迭代命令来说, 因为在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令只能对被返回的元素提供有限的保证 (offer limited guarantees about the returned elements)。
因为 scan 、 sscan 、 hscan 和 zscan 四个命令的工作方式都非常相似, 所以这个文档会一并介绍这四个命令, 但是要记住:
- sscan 命令、 hscan 命令和 zscan 命令的第一个参数总是一个数据库键。
- 而 scan 命令则不需要在第一个参数提供任何数据库键 —— 因为它迭代的是当前数据库中的所有数据库键。
scan 命令的基本用法 scan 命令是一个基于游标的迭代器(cursor based iterator): scan 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 scan 命令的游标参数, 以此来延续之前的迭代过程。 当 scan 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。 以下是一个 scan 命令的迭代过程示例: redis 127.0.0.1:6379> scan 0 1) "17" 2) 1) "key:12" 2) "key:8" 3) "key:4" 4) "key:14" 5) "key:16" 6) "key:17" 7) "key:15" 8) "key:10" 9) "key:3" 10) "key:7" 11) "key:1" redis 127.0.0.1:6379> scan 17 1) "0" 2) 1) "key:5" 2) "key:18" 3) "key:0" 4) "key:2" 5) "key:19" 6) "key:13" 7) "key:6" 8) "key:9" 9) "key:11" 在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。 第二次迭代使用的是第一次迭代时返回的游标, 也即是命令回复第一个元素的值 —— 17 。 从上面的示例可以看到, scan 命令的回复是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素。 在第二次调用 scan 命令时, 命令返回了游标 0 , 这表示迭代已经结束, 整个数据集(collection)已经被完整遍历过了。 以 0 作为游标开始一次新的迭代, 一直调用 scan 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历(full iteration)。 scan 命令的保证(guarantees) scan 命令, 以及其他增量式迭代命令, 在进行完整遍历的情况下可以为用户带来以下保证: 从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的所有元素都会被完整遍历返回; 这意味着, 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。 然而因为增量式命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点: 同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。 如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。 scan 命令每次执行返回的元素数量 增量式迭代命令并不保证每次执行都返回某个给定数量的元素。 增量式命令甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。 不过命令返回的元素数量总是符合一定规则的, 在实际中: 对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素; 而对于一个足够小的数据集来说, 如果这个数据集的底层表示为编码数据结构(encoded data structure,适用于是小集合键、小哈希键和小有序集合键), 那么增量迭代命令将在一次调用中返回数据集中的所有元素。 最后, 用户可以通过增量式迭代命令提供的 count 选项来指定每次迭代返回元素的最大值。 count 选项 虽然增量式迭代命令不保证每次迭代所返回的元素数量, 但我们可以使用 count 选项, 对命令的行为进行一定程度上的调整。 基本上, count 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。 虽然 count 选项只是对增量式迭代命令的一种提示(hint), 但是在大多数情况下, 这种提示都是有效的。 count 参数的默认值为 10 在迭代一个足够大的、由哈希表实现的数据库、集合键、哈希键或者有序集合键时, 如果用户没有使用 match 选项, 那么命令返回的元素数量通常和 count 选项指定的一样, 或者比 count 选项指定的数量稍多一些。 在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 count 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。 并非每次迭代都要使用相同的 count 值。 用户可以在每次迭代中按自己的需要随意改变 count 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。 match 选项 和 keys 命令一样, 增量式迭代命令也可以通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素, 这一点可以通过在执行增量式迭代命令时, 通过给定 match <pattern> 参数来实现。 以下是一个使用 match 选项进行迭代的示例: redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood (integer) 6 redis 127.0.0.1:6379> sscan myset 0 match f* 1) "0" 2) 1) "foo" 2) "feelsgood" 3) "foobar" 需要注意的是, 对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。 以下是这种情况的一个例子: redis 127.0.0.1:6379> scan 0 MATCH *11* 1) "288" 2) 1) "key:911" redis 127.0.0.1:6379> scan 288 MATCH *11* 1) "224" 2) (empty list or set) redis 127.0.0.1:6379> scan 224 MATCH *11* 1) "80" 2) (empty list or set) redis 127.0.0.1:6379> scan 80 MATCH *11* 1) "176" 2) (empty list or set) redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 1) "0" 2) 1) "key:611" 2) "key:711" 3) "key:118" 4) "key:117" 5) "key:311" 6) "key:112" 7) "key:111" 8) "key:110" 9) "key:113" 10) "key:211" 11) "key:411" 12) "key:115" 13) "key:116" 14) "key:114" 15) "key:119" 16) "key:811" 17) "key:511" 18) "key:11" 如你所见, 以上的大部分迭代都不返回任何元素。 在最后一次迭代, 我们通过将 count 选项的参数设置为 1000 , 强制命令为本次迭代扫描更多元素, 从而使得命令返回的元素也变多了。 并发执行多个迭代 在同一时间, 可以有任意多个客户端对同一数据集进行迭代, 客户端每次执行迭代都需要传入一个游标, 并在迭代执行之后获得一个新的游标, 而这个游标就包含了迭代的所有状态, 因此, 服务器无须为迭代记录任何状态。 中途停止迭代 因为迭代的所有状态都保存在游标里面, 而服务器无须为迭代保存任何状态, 所以客户端可以在中途停止一个迭代, 而无须对服务器进行任何通知。 即使有任意数量的迭代在中途停止, 也不会产生任何问题。 使用错误的游标进行增量式迭代 使用间断的(broken)、负数、超出范围或者其他非正常的游标来执行增量式迭代并不会造成服务器崩溃, 但可能会让命令产生未定义的行为。 未定义行为指的是, 增量式命令对返回值所做的保证可能会不再为真。 只有两种游标是合法的: 在开始一个新的迭代时, 游标必须为 0 。 增量式迭代命令在执行之后返回的, 用于延续(continue)迭代过程的游标。 迭代终结的保证 增量式迭代命令所使用的算法只保证在数据集的大小有界(bounded)的情况下, 迭代才会停止, 换句话说, 如果被迭代数据集的大小不断地增长的话, 增量式迭代命令可能永远也无法完成一次完整迭代。 从直觉上可以看出, 当一个数据集不断地变大时, 想要访问这个数据集中的所有元素就需要做越来越多的工作, 能否结束一个迭代取决于用户执行迭代的速度是否比数据集增长的速度更快。 可用版本: >= 2.8.0 时间复杂度: 增量式迭代命令每次执行的复杂度为 O(1) , 对数据集进行一次完整迭代的复杂度为 O(N) , 其中 N 为数据集中的元素数量。 返回值: scan 命令、 sscan 命令、 hscan 命令和 zscan 命令都返回一个包含两个元素的 multi-bulk 回复: 回复的第一个元素是字符串表示的无符号 64 位整数(游标), 回复的第二个元素是另一个 multi-bulk 回复, 这个 multi-bulk 回复包含了本次被迭代的元素。 scan 命令返回的每个元素都是一个数据库键。 sscan 命令返回的每个元素都是一个集合成员。 hscan 命令返回的每个元素都是一个键值对,一个键值对由一个键和一个值组成。 zscan 命令返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。
事务操作
redis-py 默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用 pipline 实现一次请求指定多个命令,并且默认情况下一次 pipline 是原子性操作。
import redis pool = redis.ConnectionPool(host='192.168.22.132', port=6379) conn = redis.Redis(connection_pool=pool) # pipe = conn.pipeline(transaction=False) pipe = conn.pipeline(transaction=True) pipe.set('name', 'root') pipe.set('role', 'root') pipe.execute()
Java博客目录 | Python博客目录 | C#博客目录