Redis-Python

本文最后更新于:2020年11月19日 晚上

信息

redis-py

redis包为python连接 Redis键值数据库 提供了接口。

文档

github地址:https://github.com/andymccurdy/redis-py/
一些中文函数参考:https://www.runoob.com/w3cnote/python-redis-intro.html

要求

Python2.7 或 Python3.5+

使用

安装

1
pip install redis

简单使用

1
2
3
4
5
6
>>> import redis
>>> r = redis.Redis(host='localhost', port=6379, db=0)
>>> r.set('foo', 'bar')
True
>>> r.get('foo')
b'bar'

python3.x版本,默认情况下,所有的响应都会返回btyes类型数据
如果觉得所有的响应都应该被解码,可以在Redis.__init__填入参数decode_responses=True。如此一来,所有的返回都会被解码。

1
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)

更多细节

连接池

在后台,redis-py使用一个连接池去管理 连接到Redis服务的连接
默认情况下,你创建的每一个Redis实例都会拥有一个自己的连接池
你也可以使用 已创建的连接池实例 来进行连接

1
2
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)

连接

ConnectionPools管理一组连接实例
redis-py提供两种类型的连接

  • 基于TCP端口的连接,默认
  • 基于Unix socket文件的连接,需要redis服务器开启
1
2
>>> r = redis.Redis(unix_socket_path='/tmp/redis.sock')
>>> pool = redis.ConnectionPool(connection_class=YourConnectionClass, your_arg='...', ...)

定时连接检查

当出现了网络问题,会抛出ConnectionError错误
redis-py提供能定期检查连接的功能
你可以传递health_check_interval参数给Redis或者 ConnectionPool
health_check_interval参数的值必须是int类型

  • 0
    默认值,关闭连接检查
  • 一个正数整数n
    连接检查功能启用,每过n秒检查一次连接

解析器类

解析器类被用于处理从Redis服务器返回来的响应
redis-py提供了两种解析器类型:

  • PythonParser
  • HiredisParser

默认情况下,redis-py会先尝试使用HiredisParser,要是发现并没有安装,那么会使用PythonParser
强烈建议你使用HiredisParser。它的解析效率比另外的那个快十倍以上。这个速度差距在进行多key查询的时候会更加明显。

Hiredis是由Redis官方团队基于C语言编写的解析库。

Hiredis安装

1
pip install hiredis

响应回调

client类用一组回调 来将Redis响应转换为合适的python类型
这些回调定义在Redis客户端里一个叫RESPONSE_CALLBACKS的字典中

你可以通过set_response_callback方法添加自定义回调
这个方法接收两个参数:命令名 和 对应的回调类
这种修改方式仅对于被添加的的实例有效,如果你想定义一个全局的回调类,你应该修改RESPONSE_CALLBACKS类字典

回调类接受至少一个参数:响应内容,关键字参数作为命令调用时的参数

线程安全

Redis实例是线程安全的
但是,由于Redis``SELECT命令能选择当前所要使用的database。每次选择database过后。当前选择的database会被保留下来,直到选择另一个database或者关闭连接
因此,redis-py没有在客户端实现实现SELECT命令。因为它可能会导致数据库的切换。

如果你在同一个程序中使用多个Redis``databases,你应该为每一个数据库创建一个单独的实例(或连接池)

Pipelines

PipelinesRedis类的一个子类,支持缓存多个命令,然后作为单个请求发送。通过减少TCP请求次数来达到提供性能的目的。
Pipelines简单使用例子:

1
2
3
4
5
6
7
8
9
10
11
>>> 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, b'baz']

Pipelines的实现采用流式API,故而你可以采用以下链式调用的方式:

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

Pipelines默认以原子性(事务)的形式执行所有缓存的命令,你也可以禁用这一行为:

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

WATCH命令提供了在事务之前检测一个或多个key值的变化。一旦在事务执行之前,某个值发生了变化,那么事务将被取消然后抛出WatchError 异常。
利用watch我们可以实现client-side incr命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>>> 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

有一个非常方便的方法transaction方法来简化这一操作:它包含handling and retrying watch errors的样板代码。第一参数为callable(这个callable只能接受一个Pipeline参数),及多个需要被WATCHkeys

1
2
3
4
5
6
7
8
>>> 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]

暂未翻译剩余部分比较多

详见github文档