rdis-py 2.4.13 documents
来源:互联网 发布:废除 网络中立 知乎 编辑:程序博客网 时间:2024/06/11 08:52
Redis 官方Redis API
StrictRedis Class一直遵从Redis 官方API语法。
- 例外情况:
SELECT: 没有实现,请查看Thread Safety 章节的解释
DEL: ‘del’ 转换为了Python语法,在redis-py 中为 ‘delete’
CONFIG GET|SET: 分别实现了’config_set’ 和’config_get’
MULTI/EXEC: 作为Pipeline 类的一部分实现,在调用pipeline方法时指定’use_transaction=True’,当pipeline语句被执行的时候,会使用MULTI和EXEC(将其封装起来)执行pipeline
SUBSCRIBE/LISTEN: 与pipeline 相似,单独实现了一个PubSub类,在已有基础连接的状态下,不允许执行non-public命令。在redis client
调用pubsub方法时会返回一个PubSub 实例,使用该实例 可以订阅频道,收听消息。在pipeline和PubSub类都可调用PUBLISH.
Redis Class,是StrictRedis的子类,重写了部分方法命令,可以向后兼容旧版本redids-py
- 被封装或改造的方法:
LREM:将’num’和’value’参数逆序,会给 ‘num’提供一个默认值0,
ZADD: Redis 官方文档指定’score’参数在’value’之前,在Redis 类的参数格式为:name1,score1,name2,score2,… 这种封装的格式转换实现的效率很高,不会影响当前执行状态。
SETEX: ‘time’和’value’参数逆序
class redis.Redis(host='localhost', port=6379, db=0, password=None, socket_timeout=None, connection_pool=None, charset='utf-8', errors='strict', decode_responses=False, unix_socket_path=None) #Redis类提供对旧版本redis-py 向后兼容,将一些命令参数改变为更加符合python格式,或更加合理。
不同点,具体用法参考StrictRedis类中的实例:
lrem(name, value, num=0) #将第一个在name列表中 与'value'相同的元素'num'删除 #'num'参数值对操作的影响: #1.num > 0: 按照从前往后的顺序 ,删除与之相等的元素; #2.num < 0: 按照从后往前的顺序,删除与之相等的元素; #3.num = 0: 删除所有与之相等的元素。pipeline(transaction=True, shard_hint=None) #返回一个新的pipeline对象,将多个命令放在队列中,供以后执行。'transaction'确定是否将所有队列中的命令按照原子性执行。将部分原子性操作分组执行,能够有效的减少clien 与 server的网络交互。setex(name, value, time) #给与name 相同名称的key 设置 value 为value, 在time时间过后超时,time可用 整型数字表示,也可用python timedelta objectzadd(name, *args, **kwargs) #注意 :参数顺序与Redis 官方ZADD的不同,为保持向后兼容,该方法接收参数格式为:name1,score1,name2,score2;但是官方Redis文档希望是:scroe1,name1,socre2,name2. #如果你想使用标准语法,可以考虑使用StrictRedis 类。 #给与name 相同名称的key设置多对(element-name,score)的值,有两种设置方式: #作为数组或列表,*args, 格式如下:name1,score1,name2,score2, #作为字典,**kwargs,格式如下:name1=score1,name2=score2... #下面的例子会添加4对值给名称为 'my-key'的key: redis.zadd(‘my-key’, ‘name1’, 1.1, ‘name2’, 2.2, name3=3.3, name4=4.4)
StrictRedis类是Redis 协议的实现,提供了所有的Redis 命令的python接口;
主要使用Connection 和Pipeline 来驱动,实现了在Redis client和Redis server之间一个命令怎样发送和接收的。
class redis.StrictRedis(host='localhost', port=6379, db=0, password=None, socket_timeout=None, connection_pool=None, charset='utf-8', errors='strict', decode_responses=False, unix_socket_path=None)#redis.StrictRedis(...)的方法与redis.Redis(...)是一致的,区别就是上述不同点。详细命令列表请参考https://kushal.fedorapeople.org/redis-py/html/api.html#redis.StrictRedis """Normal Key-Values Operation:""" append(key, value) #为该key追加string 类型value,如果 value不存在则创建,然后返回新的value长度 >>> r.append('test','test is ok') 10L debug_object(key) #返回关于该key的特定元信息的版本 >>> r.debug_object('lb') {'encoding': 'embstr', 'refcount': 1, 'lru_seconds_idle': 289, 'lru': 2267149, 'at': '00007FEC3B00A820', 'serializedlength': 19, 'type': 'Value'} decr(name, amount=1) #对名称为name的key值做amunt次递减,如果key 不存在,amount 值会初始化为0 >>> r.getset('integer',128) >>> r.decr('integer',amount=2) 126 delete(*names) #删除一个或多个name指定的key >>> r.delete('lb') 1 exists(name) #判断key是否存在,然后返回一个布尔值 >>> r.exists('lb') False >>> r.exists('integer') True expire(name, time) #给名称为name的key 设置一个超时,time可以是整型,也可以是python 的datetime对象 >>> r.expire('integer',60) True get(name) #返回名称为name的key 的值,如果key不存在,返回None >>> r.get('test') 'test is ok' incr(name, amount=1) #对名称为name的key的值递增amount次,如果key不存在,value则会初始化为amount >>> r.getset('bg',234) >>> r.incr('bg',amount=10) 244 >>> r.incr('bh',amount=9) 9 ttl(name) #当name处于超时阻塞的时候返回已耗用的秒数 r.ttl('q') type(name) #返回key的类型 >>> r.type('q') 'set' >>> r.type('tha') 'hash' set(name, value) #设置key name 的值为value >>> r.set('fu','ck') True setex(name, time, value) #在time 时间内将value 设置为key name,time可以是整型,或python datetime >>> r.setex('qwe',3,1223456) True setnx(name, value) #如果key name不存在的话,将value设置为key name的value >>> r.setnx('qwe',1223456) True persist(name) #删除name的 expiration >>> r.persist('tha') False rename(src, dst) #将key name 由src rename为dst >>> r.rename('lss','llss') True renamenx(src, dst) #如果dst 不存在,则将key name 由src rename 为 dst >>> r.renamenx('llss','lss') True"""List Value Operation:""" lpush(name, *values) #将value 压入到名称为name的list的头部 >>> r.lpush('lp',1,2,3,4) 4L >>> r.lpush('lps',(1,2,3,4)) 1L lpop(name) #删除并返回该名称为name的list的第一个元素 >>> r.lpop('lp') '4' >>> r.lpop('lps') '(1, 2, 3, 4)' blpop(keys, timeout=0) #从名称为name的key的第一个非空列表LPOP一个值 #如果该key 没有一个列表支持LPOP值,则会timeout制定的时间内阻塞,或者有值被push到其中一个list中, #如果timeout值为0,则会无限期阻塞。 >>> r.blpop('lp') ('lp', '3') brpoplpush(src, dst, timeout=0) #从src的尾部pop一个value,并将其push到dst的头部,然后返回该值 #该命令会在其中任何一个条件先出现的情况时发生阻塞,src没有一个value,timeout超时;timeout 为0 会一直阻塞. >>> r.brpoplpush('lp','lpdest',timeout=1) '1' lpushx(name, value) #如果list name 存在,则会将讲value 压入到list头部 >>> r.lpush('lss',1,2,3,3,4,45) 6L lset(name, index, value) #设置list name在index下标的值为value >>> r.lset('lss',2,45) True lindex(name, index) #返回list name在Index位置的条目 #支持负数下表如-1,将从list尾部返回第一个条目 >>> r.lindex('lss',2) '45' linsert(name, where, refvalue, value) #将value插入到list name中,是否立即返回取决于插入位置在refvalue 前面或后面, #如果成功插入返回list的长度,如果refvalue 不存在插入失败返回-1. '''参数: name: redis的name where: BEFORE(前)或AFTER(后) refvalue: 列表内的值 value: 要插入的数据''' >>> r.linsert('lss','BEFORE',45,999) 7 llen(name) #返回list name 的长度 >>> r.llen('lss') 7 rpop(name) #删除list的最后一个条目,并返回该条目 >>> r.rpop('lss') '1' rpoplpush(src, dst) #RPOP src list 的一个值,并自动将该值LPUSH到dst list,然后返回该值 >>> r.rpoplpush('lss','newl') '2' rpush(name, *values) #将value 压入到list name 的尾部 >>> r.rpush('lss',909,808,707) 8L rpushx(name, value) #如果该list 存在,则将value压入到list 尾部。 >>> r.rpushx('lss',707) 9 >>> r.rpushx('lss',77777) 10 lrange(name, start, end) #返回list name 在下标start,end之间的切片; start,end可以为负数,与python切片的方法中标记法一致 >>> r.lpush('ss',1,2,2,3,3,4,4,55,6,9) 10L >>> r.lrange('ss',1,4) ['6', '55', '4', '4'] lrem(name, count, value) #删除list name中,第count次出现的与value相等的值 count 在一下情况下的影响如下: count > 0,从头到尾判断value,从头部移除; count < 0,从后往前判断value,从尾部移除; count = 0,删除所有与value 相等的条目。 >>> r.lrem('ss',2,2) 2L ltrim(name, start, end) #将list name不在start与end之前的条目删除 start,end可以为负数,与python切片的方法中标记法一致 >>> r.ltrim('ss',1,4) True mget(keys, *args) #将多个key的多个值按照有序列表返回 >>> r.mget('ss','ls') [None, '[1, 2, 3, 4, 5, 56]']"""Bits Operation:""" getbit(name, offset) #判断键name在位移/偏移量offset的value,返回一个布尔值 >>> r.getbit('test',2) 1 >>> r.getbit('test',0) 0 >>> r.getbit('test',3) 1 setbit(name, offset, value) #在name中标记offset作为一个value,然后判断offset之前的value返回布尔值 #对二进制表示位进行操作 ''' name:redis的name offset,位的索引(将值对应的ASCII码变换成二进制后再进行索引) value,值只能是 1 或 0 ''' str="345" r.set("name",str) for i in str: print(i,ord(i),bin(ord(i)))#输出 值、ASCII码中对应的值、对应值转换的二进制 ''' 输出: 51 0b110011 52 0b110100 53 0b110101''' r.setbit("name",6,0)#把第7位改为0,也就是3对应的变成了0b110001 print(r.get("name"))#输出:145"""String Values Operation:""" getrange(key, start, end) #返回Key值字符串的子字符串,根据offset的start,end做判断 >>> r.getrange('test',1,3) 'est' strlen(name) #返回name的value中存储的byte数 >>> r.getset('str','asdfghjkjdhsgafs') >>> r.strlen('str') 16 substr(name, start, end=-1) #返回key name的位于下标start, end 之间的子字符串;start,end为整型。 >>> r.substr('str',3,-5) 'fghjkjdhs' setrange(name, offset, value) #从offset开始覆盖name的value的bytes,如果覆盖后的value长度超过原value,则新value则比之前大很多;如果仅是覆盖的部分就比原value 长很多,则不会覆盖,返回新value 的长度。 >>> r.setrange('qwe',12,234567) 18 >>> r.setrange('qwe',7,2345670987654321234567890) 32"""Sets Values Operation:""" sadd(name, *values) #将value 添加到set name中 >>> r.sadd('s',9,9,7,6) 3 scard(name) #返回set name中的元素数量 >>> r.scard('s') 3 sdiff(keys, *args) #返回指定key值set的不同 >>> r.sadd('q',9,9,7,6) 3 >>> r.sdiff('q','s') set([]) >>> r.sadd('q',9,9,7,6,3,4,6) 2 >>> r.sdiff('q','s') set(['3', '4']) sdiffstore(dest, keys, *args) #将指定的keys的不同值保存到新的set dest中,并返回dest set的key 的数量 >>> r.sdiffstore('dests','q','s') 2 sinter(keys, *args) #返回指定keys 的交集 >>> r.sinter('q','s') set(['9', '7', '6']) sinterstore(dest, keys, *args) #将keys 的交集保存在set dest中,然后返回dest中key的数量 >>> r.sinterstore('destq23','q','s') 3 sismember(name, value) #判定value是不是set name中的成员,返回布尔值。 >>> r.sismember('s',3) False >>> r.sismember('s',7) True slaveof(host=None, port=None) #设置Redis server为(host,port)的从属(slave),如果调用参数(host,port)为空则为(master)主数据库实例 smembers(name) #返回set 的所有成员 >>> r.smembers('q') set(['9', '3', '4', '7', '6']) smove(src, dst, value) #自动将value从src移动到dst >>> r.smove('q','s',3) True spop(name) #随机删除set name中的值并返回 >>> r.spop('s') '6' srandmember(name) #随机set name返回一个值。 >>> r.srandmember('s') '9' srem(name, *values) #从set name中删除value >>> r.smembers('s') set(['9', '3', '7']) >>> r.srem('s',9,3) 2 sunion(keys, *args) #返回keys的并集 >>> r.sunion('q','s') set(['9', '4', '7', '6']) sunionstore(dest, keys, *args) #将keys的并集保存到dest,并返回dest的成员数目 >>> r.sunionstore('dest11','q','s') 4 getset(name, value) #如果key 不存在,将value设置为名称为name的key值,并自动返回value,key name。 >>> r.getset('test','new hello') 'test is ok' >>> r.getset('haha','new hello') >>> r.get('haha') 'new hello' sort(name, start=None, num=None, by=None, get=None, desc=False, alpha=False, store=None) #将 list 或set排序并返回。 >>> r.sort('q') ['4', '6', '7', '9']"""Hash Values Operation:""" hset(name, key, value) #将key添加到value在 名称为name的hash表中,如果HSET新创建了条目,返回1,否则返回0 >>> r.hset('haa','ha','123') 1L hdel(name, *keys) #将名称为name的hash表的keys 删除 >>> r.hdel('haa','ha') hexists(name, key) #判断key是否存在于名称为name的hash表中,返回布尔值 >>> r.hexists('haa','ha') False hget(name, key) #返回名称为name的hash表中key 的value >>> r.hset('haa','we','56') 1L >>> r.hget('haa','we') '56' hgetall(name) #将hash表的name/value 作为一个python 字典对象返回 >>> r.hgetall('haa') {'we': '56'} hincrby(name, key, amount=1) #对名称为name的hash表的key的value 递增amount次 >>> r.hincrby('haa','we',3) 59L hkeys(name) #返回名称为name的hash表的keys,作为list返回 >>> r.hset('haa','wi','96') 1L >>> r.hkeys('haa') ['we', 'wi'] hlen(name) #返回名称为name的hash表的,所有元素的数量 >>> r.hlen('haa') 2 hmget(name, keys, *args) #返回命令相同键值的列表 >>> r.hmget('haa','wi') ['96'] >>> r.hmget('haa','wi','we') ['96', '59'] hmset(name, mapping) #每个mapping映射字典中的键设置为hash name的值 >>> r.hmset('tha',{'q':1,'w':2}) True >>> dic={"a1":"aa","b1":"bb"} >>> r.hmset("mha",dic) True hsetnx(name, key, value) #如果hash表name没有该key,设置key到value,如果HSETNX创建了新条目返回1,否则返回0 >>> r.hsetnx('haa','wi',77) 0L >>> r.hsetnx('haa','wq',77) 1L hvals(name) #返回hash表name中的value列表 >>> r.hvals('mha') ['aa', 'bb'] mset(mapping) #设置mapping 字典中每个key为其对应的值 >>> r.mset({'qw':1234,'rt':'good'}) True msetnx(mapping) #在任何key都没有被设置的情况下,设置mapping 字典中每个key为其对应的值 >>> r.msetnx({'ss':12,'ww':33}) True"""Zadd Values Operation:""" zadd(name, *args, **kwargs) #将多组score,element-name添加到key name中,有以下两种格式: # As *args,列表形式:score1,name1,score2,name2... # As **kwargs字典形式:name1=score1,name2=score2... # 下面的这个例子将会添加四组值到key 'my-key', redis.zadd(‘my-key’, 1.1, ‘name1’, 2.2, ‘name2’, name3=3.3, name4=4.4) >>> r.zadd('good2','name1',1,'name2',2,) 2 >>> r.zadd('mykey','n1',11,'n3',44,name5=5.5,name6=8.8) 4 zcard(name) #返回顺序集合中的元素个数 >>> r.zcard('mykey') 4 zincrby(name, value, amount=1) #对顺序集合 name的value递增amount次 >>> r.zincrby('mykey',10,3) 3.0 >>> r.zincrby('mykey','n1',3) 14.0 zinterstore(dest, keys, aggregate=None) #将指定的keys顺序集合的元素做交集,然后放到新的集合dest中,在dest中的元素将会根据aggregate参数做aggregate处理,如果aggregate=None,会执行求和。 >>> r.zinterstore('dst3',('good2','mykey'),aggregate='MAX') 0L >>> r.zinterstore('dst3',('good2','mykey')) 0L zrange(name, start, end, desc=False, withscores=False, score_cast_func=<type 'float'>) #返回set name的在start,end下标范围的values,并按升序排序 r.zrange('mykey',1,3,) ['11', 'name5', 'name6'] zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=<type 'float'>) #返回set name在最大和最小范围内的values >>> r.zrangebyscore('mykey',0,10000,) ['10', '11', 'name5', 'name6', 'n1', 'n3'] zrank(name, value) #判定value是否在set name中的顺序,并将该序返回。 >>> r.zrank('mykey',10) 0 >>> r.zrank('mykey',11) 1 zrem(name, *values) #从已排序的set name中,删除value >>> r.zrem('mykey',11) 1 zremrangebyrank(name, min, max) #删除已排序的set name的所有在min.max序列之间的元素,并将他们返回。 >>> r.zremrangebyrank('meykey',0,10) 0 zremrangebyscore(name, min, max) #删除已排序的set name的所有在min.max序列之间的score,并将他们返回。 >>> r.zremrangebyscore('mykey',0,20) 4 zrevrange(name, start, num, withscores=False, score_cast_func=<type 'float'>) #返回已排序的set name中按照描述的排序范围内的值 >>> r.zrevrange('mykey',0,11) ['n3'] zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=<type 'float'>) #返回已排序的set name中按照描述的排序中在最小和最大范围内的值 >>> r.zrevrangebyscore('mykey',-1,100) [] zrevrank(name, value) #判断value是否在set name中递减顺序,并返回顺序 >>> r.zadd('mk',n1=1,n2=22,n3=33,n4=44,n5=55,n6=66) 6 >>> r.zrevrank('mk','n2') 4 zscore(name, value) #返回set name中element-value的score >>> r.zscore('mk','n4') 44.0 zunionstore(dest, keys, aggregate=None) #将keys指定的集合做多结构体排序到新的set dest ,score 将会按照aggregate参数做处理,如过参数为None,则做求和。 >>> r.zunionstore('destz',('mykey','mk')) 6L"""DB Configuration Operation:""" config_get(pattern='*') #返回基于pattern 的基本配置的字典 >>> r.config_get(pattern='bind') {'bind': '127.0.0.1'} >>> r.config_get(pattern='port') {'port': '6379'} >>> config_set(name, value) #为名称为name 的元素设置值为value >>> r.config_set('repl-timeout', '45') True dbsize() #返回当前database 的所有key的数量 >>> r.dbsize() 5L flushall() #删除当前主机的所有database的所有key flushdb() #删除当前database的所有key >>> tmps.flushdb() True info() #将Rredis Server 相关信息作为一个字典返回 keys(pattern='*') #返回与pattern 匹配的key列表 >>> r.keys('b*') ['bg', 'bh'] lastsave() #返回Redis Server最后一次保存数据到硬盘的时间 >>> r.lastsave() datetime.datetime(2017, 5, 22, 16, 42, 31) set_response_callback(command, callback) #设置一个自定义的回调响应 shutdown() #关闭Redis Server r.shutdown() save() #通知Redis Server将数据保存到硬盘,在没有保存完成之前该操作会一直阻塞。 >>> r.save() True bgsave() #告诉Redis Server将其数据保存到硬盘上,与save()方法不同,这个方法是异步执行的,会立刻返回。 >>> r.bgsave() True move(name, db) #将key移动到另一个database db >>> r.move('ss',db=3) True object(infotype, key) #返回key的 encoding, idletime, or refcount >>> r.object('refcount','ls') 1 >>> r.object('encoding','ls') 'embstr' >>> r.object('idletime','ls') 1022 parse_response(connection, command_name, **options) #解析Redis Server的响应消息 ping() #ping 检查Redis Server >>> r.ping() True bgrewriteaof() #告诉Redis Server拿内存数据重写AOF文件 >>> r.bgrewriteaof() True echo(value) #对Redis server输出一个字符串value并返回 >>> r.echo('hello,world') 'hello,world' randomkey() #返回 random key的名称 >>> r.randomkey() 'lss'"""Commands Operation:""" execute_command(*args, **options) #执行一个命令,并返回解析的结果 transaction(func, *watches, **kwargs) #可以作为在监控所有在watches指定的keys时,将执行可调用函数作为transaction的便捷方法,传入参数应该是一个Pipeline 对象 unwatch() #unwatch key值,如果key不存在,则什么都不做 #(Flushes all the previously watched keys for a transaction. #If you call EXEC or DISCARD, there's no need to manually call UNWATCH.) watch(*names) # watch key值,如果key不存在,则什么都不做 (Marks the given keys to be watched for conditional execution of a transaction.) pipeline(transaction=True, shard_hint=None) #返回一个新的pipeline对象,支持执行多条语句仅对Redis Server请求一次. 通过减少Redis Client和Server之间back-and-forth TCP会话报文传递,显著的提升一组语句的执行效率。 publish(channel, message) #在channel发布消息, 返回会收听消息的订阅者数量 pubsub(shard_hint=None) #返回一个 Publish/Subscribe 对象,在该实例中可以订阅频道,收听发布的消息 lock(name, timeout=None, sleep=0.1) #使用key 名称name,返回一个与threading.Lock行为 类似的LOCK对象 #如果指定timeout,则会在timeout超时时释放LOCK,默认情况下回一直保持LOCK,直到release()被调用 #当LOCK处于阻塞状态或,其他client持有LOCK状态,则会以sleep为周期检查LOCK状态
Exception:exception redis.AuthenticationErrorexception redis.ConnectionErrorexception redis.DataErrorexception redis.InvalidResponseexception redis.PubSubErrorexception redis.RedisErrorexception redis.ResponseErrorexception redis.WatchError
Response Callbacks
Client 类 使用一个回调集合来讲Redis responses 映射为python type,在Redis client 类中RESPONSE_CALLBACKS定义了一些Callbacks
用户自定义的Callbacks 可以通过 set_response_callback方法添加到每个实例中,该方法接收两个参数,一个是命令名称,一个是Callbacks.使用该方法添加的Callbacks仅在该实例回调的时候有效。如果你想定义或重写一个全局Callbacks,你需要创建一个Redis client类的子类,并将Callback 添加到 REDIS_CALLBACKS的字典中。
Response callbacks 至少需要一个参数:Redis server的response,为了在后续控制如何中断response, Keyword arguments也是可以接收的。这个Keyword arguments 是在command’s call to execute_command期间指定的。 The ZRANGE implementation demonstrates the use of response callback keyword arguments with its “withscores”argument.
Thread Safety
Redis client 实例可以安全的在线程间共享。内部连接实例在命令执行完后是从连接池回收,在命令执行完后直接返回到连接池,命令执行时从不会改变client connection 状态。
然而,需要告诫一下:Redis SELECT命令,SELECT命令允许你在当前连接在使用的情况下切换database,被选择的database会一直保有,直到其他database被选择,或连接被关闭。在连接中创建的事务也会返回到连接其他databases的连接池中。
因此,redis-py没有在client实例中实现SELECT命令。如果你想在一个应用中使用多个redis databases,应该为每一个database创建单独的client instance.
在线程之间透传PubSub对象,和Pipeline对象会不安全。
Pipelines
Pipelines are Redis基础类的子类,支持执行多条语句仅对Redis Server请求一次. 通过减少Redis Client和Server之间back-and-forth TCP会话报文传递,显著的提升一组语句的执行效率。
Pipelines 最简单的例子:
>>> r = redis.Redis(...)>>> r.set('bing', 'baz')>>> # Use the pipeline() method to create a pipeline instance>>> pipe = r.pipeline()>>> # The following SET commands are buffered>>> pipe.set('foo', 'bar')>>> pipe.get('bing')>>> # the EXECUTE call sends all buffered commands to the server, returning>>> # a list of responses, one for each command.>>> pipe.execute()[True, 'baz']
为了使用起来简单,所有的语句会加载到pipeline缓存,返回pipeline对象:
>>> pipe.set('foo', 'bar').sadd('faz', 'baz').incr('auto_number').execute()[True, True, 6]
另外,默认情况下 ,pipeline也可确保缓存里的语句会作为一组原子型语句执行,如果你想禁用piprline的原子属性,但还想将语句放入缓存,则需要关闭transactions。
>>> pipe = r.pipeline(transaction=False)
一个简单事实是,当我们需要原子处理的时候,需要从Redis prior 中回收之前的处理值。举一个实例,让我们假设python没有INCR命令,但我们需要创建一个INCR原子版本。
在python中已经实现 了在本地GET 值,设置值后返回。然而,这个操作不是原子的,因为,多个Client可能会在同一时刻做同样的操作,每个client都会GET到相同的值。
加入WATCH 命令,WATCH提供了能监控一个或多个key 之前状态,去执行处理或传输。如果一些keys在执行该事务时之前发生了变化,那么整体的处理将会取消并且抛出一个 WatchError.我们可以通过以下做法实现
Redis client-side INCR:>>> with r.pipeline() as pipe:... while 1:... try:... # put a WATCH on the key that holds our sequence value... pipe.watch('OUR-SEQUENCE-KEY')... # after WATCHing, the pipeline is put into immediate execution... # mode until we tell it to start buffering commands again... # this allows us to get the current value of our sequence... current_value = pipe.get('OUR-SEQUENCE-KEY')... next_value = int(current_value) + 1... # now we can put the pipeline back into buffered mode with MULTI... pipe.multi()... pipe.set('OUR-SEQUENCE-KEY', next_value)... # and finally, execute the pipeline (the set command)... pipe.execute()... # if a WatchError wasn't raised during execution, everything... # we just did happened atomically... break... except WatchError:... # another client must have changed 'OUR-SEQUENCE-KEY' between... # the time we started WATCHing it and the pipeline's execution... # our best bet is to just retry... continue
注意:由于Pipeline 在WATCH过程中必须绑定一个Connection,必须注意调用reset()方法使该Connection 在WATCH之后返回到Connection pool。如果Pipeline被用在一个上下文管理器内,如在上面的这个例子,reset()方法会被自动调用。当然你也可以手工显式调用reset()。
>>> pipe = r.pipeline()>>> while 1:... try:... pipe.watch('OUR-SEQUENCE-KEY')... ...... pipe.execute()... break... except WatchError:... continue... finally:... pipe.reset()
一个便捷的方法叫做”transaction”可以操控一个WATCH 处理和重试的副本,支持回调,只需要单一参数,一个pipeline对象,被WACHED的一定数量的keys。我们Redis client INCR 命令可以重写为这样,更易读的格式:
>>> def client_side_incr(pipe):... current_value = pipe.get('OUR-SEQUENCE-KEY')... next_value = int(current_value) + 1... pipe.multi()... pipe.set('OUR-SEQUENCE-KEY', next_value)>>>>>> r.transaction(client_side_incr, 'OUR-SEQUENCE-KEY')[True]
- rdis-py 2.4.13 documents
- Rdis
- Rdis 基础知识
- rdis 缓存
- Documents
- .Documents
- rdis+window+php 安装
- Rdis快速入门
- rdis和memcache的区别
- py
- py
- py
- py
- py
- py
- py
- Py
- Rdis客户端开发API包的介绍
- BZOJ1069: [SCOI2007]最大土地面积
- ajaxfileupload.js问题汇总及解决 附修复版下载
- Redis学习博客
- sparkGc
- Python中 sys.argv[]的用法
- rdis-py 2.4.13 documents
- Collections.sort() 排序算法 源码简介
- ubuntu 16.04安装 navicat
- 遍历Map的四种方法
- Eventbus3架构概要分析
- 终端提交代码到码云
- 仿微信朋友圈图片浏览器
- C语言之球体自由落体和猴子吃桃算法
- SOUI界面库 第1讲-开发环境搭建