查看参考文档

String 基本命令

  • set(name, value, ex=None, px=None, nx=False, xx=False)
    • 设置键值 默认:若不存在创建,存在修改
    • 参数:
      • ex,过期时间(秒)
        px,过期时间(毫秒)
        nx,如果设置为True,则只有name不存在时,当前set操作才执行
        xx,如果设置为True,则只有name存在时,当前set操作才执行
  • setnx(name, value)
    • 设置键值 默认:只有name不存在时,执行添加操作
  • setex(name, value, time)
    • 设置键值
    • 参数:
      • time,过期时间(数字秒 或 timedelta对象)
  • psetex(name, time_ms, value)
    • 设置键值
    • 参数:
      • time_ms,过期时间(数字毫秒 或 timedelta对象)
  • mset(*args, **kwargs)
    • 批量设置键值
    • 例如:
      • r.mset({‘name1′:’value1’.’name2′:”value2′})
      • r.mset(k1=’v1′,k2=’v2′)
  • mget(keys, *args)
    • 批量获取值
    • 例如:
      • r.mget(‘k1’, ‘k2’)
      • r.mget([‘k1’, ‘k2’])
  • getset(name, value)
    • 设置新值并获取原来的值
    • 例如:
      • r.getset(“food”, “barbecue”)
  • getrange(key, start, end)
    • 获取子序列(根据字节获取,非字符)
    • 参数:
      • name,Redis 的 name
        start,起始位置(字节)
        end,结束位置(字节)
  • setrange(name, offset, value)
    • 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
    • 参数:
      • offset,字符串的索引,字节(一个汉字三个字节)
        value,要设置的值
  • setbit(name, offset, value)
    • 对name对应值的二进制表示的位进行操作
    • 参数:
      • name,redis的name
        offset,位的索引(将值变换成二进制后再进行索引)
        value,值只能是 1 或 0
  • getbit(name, offset)
    • 获取name对应的值的二进制表示中的某位的值 (0或1)
    • 例如:
      • r.getbit(“foo1”, 0) # 0 foo1 对应的二进制 4个字节 32位 第0位是0还是1
  • bitcount(key, start=None, end=None)
    • 获取name对应的值的二进制表示中 1 的个数
    • 参数:
      • key,Redis的name
        start 字节起始位置
        end,字节结束位置
  • bitop(operation, dest, *keys)
    • 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
    • 参数:
      • operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
        dest, 新的Redis的name
        *keys,要查找的Redis的name
  • strlen(name)
    • 返回name对应值的字节长度(一个汉字3个字节)
  • incr(self, name, amount=1)
    • 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
    • 参数:
      • name,Redis的name
        amount,自增数(必须是整数)
        注:同incrby
  • incrbyfloat(self, name, amount=1.0)
    • 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
    • 参数:
      • name,Redis的name
        amount,自增数(浮点型)
  • decr(self, name, amount=1)
    • 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
    • 参数:
      • name,Redis的name
        amount,自减数(整数)
  • append(key, value)
    • 在redis name对应的值后面追加内容
    • 参数:
      • key, redis的name
        value, 要追加的字符串

默认情况下,所有响应在python3中以字节的形式返回,在python2中以str的形式返回。用户负责解码到python3字符串或python2 unicode对象。

如果应该解码客户机的所有字符串响应,用户可以指定decode_responses=True to redis . _init__。在本例中,任何返回字符串类型的Redis命令都将使用指定的编码进行解码。

小示例:

import redis
r = redis.Redis(host='localhost',port=6379,db=0)
r.set('foo','bar')
Out[4]: True
r.get('foo')
Out[5]: b'bar'

安装redis库

pip install redis

连接redis

import redis   # 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库
r = redis.Redis(host='localhost', port=6379, decode_responses=True)   # host是redis主机,需要redis服务端和客户端都启动 redis默认端口是6379 decode_response代表写入的键值对中的value为str类型,不加的话则为字节类型
r.set('name', 'junxi')  # key是"foo" value是"bar" 将键值对存入redis缓存
print(r['name'])
print(r.get('name'))  # 取出键name对应的值
print(type(r.get('name')))

连接池

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。
可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池

import redis    # 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)   # host是redis主机,需要redis服务端和客户端都起着 redis默认端口是6379
r = redis.Redis(connection_pool=pool)
r.set('gender', 'male')     # key是"gender" value是"male" 将键值对存入redis缓存
print(r.get('gender'))      # gender 取出键male对应的值

API参考

官方的Redis命令文档在详细解释每个命令方面做得很好。redis-py尝试遵循官方命令语法。有几个例外:

  • SELECT
    • 没有实现。请参阅下面线程安全部分中的说明。
  • DEL
    • “del”是Python语法中的保留关键字。因此redis-py使用“delete”代替。
  • MULTI/EXEC
    • 这些都是作为管道类的一部分实现的。默认情况下,管道在执行时使用MULTI和EXEC语句进行包装,可以通过指定transaction=False禁用该语句。请参阅下面关于管道的更多信息。
  • SUBSCRIBE/LISTEN
    • 与管道类似,PubSub作为一个单独的类实现,因为它将底层连接置于无法执行非PubSub命令的状态。从Redis客户机调用pubsub方法将返回一个pubsub实例,您可以在该实例中订阅通道并侦听消息。您只能从Redis客户端调用PUBLISH(有关问题#151的详细信息,请参阅此评论)。
  • SCAN/SSCAN/HSCAN/ZSCAN
    • 扫描命令在Redis文档中已经实现。此外,每个命令都有一个等维数迭代器方法。这纯粹是为了方便,所以用户不必在迭代时跟踪游标。对这种行为使用scan_iter/sscan_iter/hscan_iter/zscan_iter方法。

管道 (Pipelines)

管道是基本Redis类的子类,它支持在一个请求中缓冲多个命令到服务器。它们可以通过减少客户机和服务器之间来回TCP包的数量来显著提高命令组的性能。

管道的使用非常简单:

>>> r = redis.Redis(...)
>>> r.set('bing', 'baz')
>>> # 使用pipeline()方法创建一个pipeline实例
>>> pipe = r.pipeline()
>>> # 下面的SET命令被缓冲
>>> pipe.set('foo', 'bar')
>>> pipe.get('bing')
>>> # EXECUTE调用将所有缓冲命令发送到服务器,并返回
>>> # 响应列表, 每个命令对应一个
>>> pipe.execute()
[True, 'baz']

为了便于使用,所有被缓冲到管道中的命令都返回管道对象本身。因此,调用可以链接如下:

>>> pipe.set('foo', 'bar').sadd('faz', 'baz').incr('auto_number').execute()
[True, True, 6]

此外,管道还可以确保缓冲命令作为一个组自动执行。这是默认情况。如果您想禁用管道的原子性,但仍然想缓冲命令,可以关闭事务。

>>> pipe = r.pipeline(transaction=False)

输入WATCH命令。WATCH提供了在开始事务之前监视一个或多个键的功能。如果这些键中的任何一个在事务执行之前发生了更改,那么整个事务将被取消,并引发一个WatchError。要实现我们自己的客户端INCR命令,我们可以这样做:

>>> with r.pipeline() as pipe:
...     while True:
...         try:
...             # 设置一个WATCH监控key
...             pipe.watch('OUR-SEQUENCE-KEY')
...             # 设置WATCH后, 管道被立即执行
...             # 到我们告诉它重新开始缓冲命令。
...             # 这允许我们得到序列的当前值
...             current_value = pipe.get('OUR-SEQUENCE-KEY')
...             next_value = int(current_value) + 1
...             # 现在我们可以把管道恢复到缓冲模式
...             pipe.multi()
...             pipe.set('OUR-SEQUENCE-KEY', next_value)
...             # 最后,执行管道(set命令)
...             pipe.execute()
...             # 如果在执行过程中没有引发WatchError,则一切正常
...             break
...        except WatchError:
...             # 之间的另一个客户端必须更改了“OUR-SEQUENCE-KEY”
...             # 我们开始观察它和管道执行的时间。
...             # 我们最好的办法就是再试一次。
...             continue

发布和订阅 (Publish / Subscribe)

redis-py包含订阅通道并侦听新消息的PubSub对象。创建PubSub对象很容易。

>>> r = redis.Redis(...)
>>> p = r.pubsub()

一旦创建了PubSub实例,就可以订阅通道和模式。

>>> p.subscribe('my-first-channel', 'my-second-channel', ...)
>>> p.psubscribe('my-*', ...)

PubSub实例现在订阅到这些通道/模式。订阅确认可以通过读取PubSub实例中的消息来查看。

>>> p.get_message()
{'pattern': None, 'type': 'subscribe', 'channel': 'my-second-channel', 'data': 1L}
>>> p.get_message()
{'pattern': None, 'type': 'subscribe', 'channel': 'my-first-channel', 'data': 2L}
>>> p.get_message()
{'pattern': None, 'type': 'psubscribe', 'channel': 'my-*', 'data': 3L}

从PubSub实例读取的每个消息都将是一个字典,其中包含以下键。

  • type:
    • 下列之一: ‘subscribe’, ‘unsubscribe’, ‘psubscribe’, ‘punsubscribe’, ‘message’, ‘pmessage’
  • channel
    • 订阅或发布消息的通道
  • pattern
    • 匹配已发布消息的通道的模式。除“pmessage”类型外,在所有情况下都为空。
  • data
    • 消息数据。对于[un]订阅消息,这个值将是连接当前订阅的通道和模式的数量。对于[p]消息消息,这个值将是实际发布的消息。

现在让我们发个信息

# publish方法返回与通道和模式匹配的数字
# 订阅 'my-first-channel'匹配两个'my-first-channel'
# 订阅和“my-*”模式订阅,因此此消息将
# 被交付到2个通道/模式
>>> r.publish('my-first-channel', 'some data')
2
>>> p.get_message()
{'channel': 'my-first-channel', 'data': 'some data', 'pattern': None, 'type': 'message'}
>>> p.get_message()
{'channel': 'my-first-channel', 'data': 'some data', 'pattern': 'my-*', 'type': 'pmessage'}

取消订阅的工作原理与订阅一样。如果没有向[p]取消订阅传递参数,则所有通道或模式都将被取消订阅。

>>> p.unsubscribe()
>>> p.punsubscribe('my-*')
>>> p.get_message()
{'channel': 'my-second-channel', 'data': 2L, 'pattern': None, 'type': 'unsubscribe'}
>>> p.get_message()
{'channel': 'my-first-channel', 'data': 1L, 'pattern': None, 'type': 'unsubscribe'}
>>> p.get_message()
{'channel': 'my-*', 'data': 0L, 'pattern': None, 'type': 'punsubscribe'}

redis-py还允许注册回调函数来处理已发布的消息。消息处理程序只接受一个参数Message,它是一个字典,就像上面的例子一样。若要使用消息处理程序订阅通道或模式,请将通道或模式名称作为关键字参数传递,其值为回调函数。

当使用消息处理程序在通道或模式上读取消息时,将创建消息字典并将其传递给消息处理程序。在本例中,get_message()返回一个None值,因为消息已经被处理。

>>> def my_handler(message):
...     print 'MY HANDLER: ', message['data']
>>> p.subscribe(**{'my-channel': my_handler})
# 阅读订阅确认消息
>>> p.get_message()
{'pattern': None, 'type': 'subscribe', 'channel': 'my-channel', 'data': 1L}
>>> r.publish('my-channel', 'awesome data')
1
# 要使消息处理程序工作,我们需要告诉实例读取数据。
# 这可以通过几种方式实现(请参阅下面的更多内容)。我们将只使用
# 现在使用熟悉的get_message()函数
>>> message = p.get_message()
MY HANDLER:  awesome data
# 注意,my_handler回调函数打印了上面的字符串。
# `message '为None,因为消息是由我们的处理程序处理的。
>>> print message
None

如果您的应用程序对(有时是嘈杂的)订阅/取消订阅确认消息不感兴趣,您可以通过将ignore_subscribe_messages=True传递给r.pubsub()来忽略它们。这将导致所有订阅/取消订阅消息都被读取,但它们不会出现在您的应用程序中。

>>> p = r.pubsub(ignore_subscribe_messages=True)
>>> p.subscribe('my-channel')
>>> p.get_message()  # hides the subscribe message and returns None
>>> r.publish('my-channel')
1
>>> p.get_message()
{'channel': 'my-channel', 'data': 'my data', 'pattern': None, 'type': 'message'}

阅读信息有三种不同的策略。
上面的示例使用了pubsub.get_message()。在后台,get_message()使用系统的“select”模块快速轮询连接的套接字。如果有可用的数据可供读取,get_message()将读取数据,格式化消息并返回或传递给消息处理程序。如果没有要读取的数据,get_message()将立即返回None。这使得在应用程序中集成到现有的事件循环变得非常简单。

>>> while True:
>>>     message = p.get_message()
>>>     if message:
>>>         # do something with the message
>>>     time.sleep(0.001)  # be nice to the system :)

发表回复