使用 Python 操作 Redis 数据库

1. 简介

Redis 是是一个高性能的 key-value 数据库。Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。 Redis不仅仅支持简单的 key-value 类型的数据,同时还提供 list、set、zset、hash 等数据结构的存储。

Python 程序要访问 Redis,需要使用第三方模块 redis。

2. 安装模块 redis

redis 是 python 访问 Redis 数据库的模块。首先检查是否已经安装了 redis 模块,在 python 交互模式下 import redis,如下所示:

>>> import redis
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'redis'

如果出现错误:ModuleNotFoundError,则表示还没有安装 redis,使用 pip3 install mysql 安装 redis,如下所示:

$ pip3 install redis
Collecting redis
...
Installing collected packages: redis
Successfully installed redis-3.5.3

3. 连接 redis 数据库

使用 redis.Redis() 方法连接 redis 数据库,示例如下:

>>> import redis
>>> db = redis.Redis(host='localhost')
>>> db.set('name', 'ZhangSan')
True
>>> db.get('name')
b'ZhangSan'
  • 在第 1 行,引入 redis 模块
  • 在第 2 行,使用 redis.Redis() 方法连接 redis 数据库,返回一个数据库连接对象 db
  • 在第 3 行,设置键 ‘name’ 的值为 ‘ZhangSan’
  • 在第 5 行,获取键 ‘name’ 的值
  • 在第 6 行,redis 数据库返回的是字节对象 b’ZhangSan’,而不是字符串 ‘ZhangSan’

在默认情况下,redis 返回的结果是字节对象,通过设定参数 decode_responses=True 使 redis 返回字符串。示例如下:

>>> import redis
>>> db = redis.Redis(host='localhost', decode_responses=True)
>>> db.set('name', 'ZhangSan')
True
>>> db.get('name')
'ZhangSan'
  • 在第 2 行,使用 decode_responses=True 的方式连接 redis 数据库
  • 在第 6 行,redis 数据库返回的是字符串 ‘ZhangSan’,而不是字节对象 b’ZhangSan’

在接下来的小节中,我们使用 decode_responses=True 的方式连接 redis 数据库,通过数据库连接对象 db 向 redis 数据库发送命令。以上连接 redis 数据库的代码将不再重复。

4. 根据键访问

4.1 设置和获取一个键

>>> db.set('name', 'imooc')
True
>>> db.get('name')
'imooc'
  • 在第 1 行,设置键 ‘name’ 的值为 ‘imooc’
  • 在第 3 行,获取键 ‘name’ 的值

4.2 设置和获取多个键

>>> db.mset({'name': 'ZhangSan', 'age': 30})
True
>>> db.mget('name', 'age')
['ZhangSan', '30']
>>> db.mget(['name', 'age'])
['ZhangSan', '30']
  • 在第 1 行,设置两个键
    • 设置键 ‘name’ 的值为 ‘ZhangSan’
    • 设置键 ‘age’ 的值为 30
  • 在第 3 行,获取两个键的值
    • mget 返回一个记录了两个键值的数组
  • 在第 5 行,获取两个键的值的另一种调用方式

4.2 删除键

>>> db.set('name', 'ZhangSan')
>>> db.get('name')
'ZhangSan'
>>> db.delete('name')
1
>>> db.get('name')
>>> db.get('name') == None
True
  • 在第 1 行,设置键 ‘name’ 的值为 ‘ZhangSan’
  • 在第 4 行,使用 delete() 方法删除键 ‘name’
  • 删除键 ‘name’ 后,db.get(‘name’) 返回 None

5. 访问字符串

5.1 获取字符串的长度

>>> db.set('name', 'www.imooc.com')
True
>>> db.strlen('name')
13
  • 在第 1 行,设置键 ‘name’ 的值为字符串 ‘www.imooc.com
  • 在第 3 行,通过 strlen() 方法获取键 ‘name’ 的值的长度

5.2 获取字符串的子串

>>> db.getrange('name', 0, 2)
'www'
>>> db.getrange('name', 4, 8)
'imooc'
>>> db.getrange('name', 10, 12)
'com'
>>>
  • 在第 1 行,获取字符串中范围为 [0, 2] 的子串,即 ‘www’
  • 在第 3 行,获取字符串中范围为 [4, 8] 的子串,即 ‘imooc’
  • 在第 5 行,获取字符串中范围为 [10, 12] 的子串,即 ‘com’

5.3 设置字符串的子串

>>> db.setrange('name', 4, 'IMOOC')
13
>>> db.get('name')
'www.IMOOC.com'
  • 在第 1 行,将字符串中从 4 开始的子串 ‘imooc’,替换为 ‘IMOOC’

6. 访问列表

6.1 创建列表

>>> db.rpush('url', 'www')
1
>>> db.rpush('url', 'imooc')
2
>>> db.rpush('url', 'com')
3
  • 方法 rpush(list, value) 将值 value 添加到列表 list 的尾部
    • 如果列表 list 不存在,会创建一个空列表
  • 在第 1 行,创建一个列表 url,将字符串 ‘www’ 添加到列表的尾部
  • 在第 2 行,将字符串 ‘imooc’ 添加到列表的尾部
  • 在第 3 行,将字符串 ‘com’ 添加到列表的尾部

6.2 访问列表

>>> db.llen('url')
3
>>> db.lindex('url', 0)
'www'
>>> db.lindex('url', 1)
'imooc'
>>> db.lindex('url', 2)
'com'
  • 在第 1 行,方法 llen(‘url’) 返回列表 url 的长度
  • 在第 3 行,llindex(‘url’, 0) 返回列表 url 中第 0 项的数据
  • 在第 5 行,llindex(‘url’, 1) 返回列表 url 中第 1 项的数据
  • 在第 7 行,llindex(‘url’, 2) 返回列表 url 中第 2 项的数据

6.3 获取指定范围的元素

>>> db.lrange('url', 0, 1)
['www', 'imooc']
>>> db.lrange('url', 0, 2)
['www', 'imooc', 'com']
  • lrange(start, stop) 返回列表中指定区间 [start, stop] 内的元素
  • 在第 1 行,获取列表 url 中范围 [0, 1] 内的 2 项元素
  • 在第 3 行,获取列表 url 中范围 [0, 2] 内的 3 项元素

6.4 在列表中插入数据

>>> db.lrange('url', 0, 2)
['www', 'imooc', 'com']
>>> db.linsert('url', 'after', 'www', '.')
4
>>> db.linsert('url', 'before', 'com', '.')
5
>>> db.lrange('url', 0, 4)
['www', '.', 'imooc', '.', 'com']
  • 在第 3 行,在数据项 ‘www’ 的后面,插入数据项 ‘.’
  • 在第 5 行,在数据项 ‘com’ 的前面,插入数据项 ‘.’
  • 在第 8 行,结果显示
    • 在 ‘www’ 和 ‘imooc’ 之间增加了一项 ‘.’
    • 在 ‘imooc’ 和 ‘com’ 之间增加了一项 ‘.’

6.5 修改列表

>>> db.lindex('url', 1)
'imooc'
>>> db.lset('url', 1, 'IMOOC')
True
>>> db.lindex('url', 1)
'IMOOC'
  • 在第 1 行,显示列表 ‘url’ 的第 1 项内容为 ‘imooc’
  • 在第 3 行,将列表 ‘url’ 的第 1 项内容修改为 ‘IMOOC’
  • 在第 5 行,显示列表 ‘url’ 的第 1 项内容为 ‘IMOOC’

6.6 将列表作为堆栈

>>> db.rpush('stack', 'www')
1
>>> db.rpush('stack', 'imooc')
2
>>> db.rpush('stack', 'com')
3
>>> db.llen('stack')
3
  • 方法 rpush(list, value) 将数据增加到列表 list 尾部,相当于堆栈的 push 操作
  • 将 3 个字符串 ‘www’、‘imooc’、‘com’ 依次压入到堆栈 stack 中
  • 此时堆栈 stack 的长度为 3
>>> db.rpop('stack')
'com'
>>> db.rpop('stack')
'imooc'
>>> db.rpop('stack')
'www'
>>> db.llen('stack')
0
  • 方法 rpop(list) 将数据从列表 list 尾部删除,相当于堆栈的 pop 操作
  • 从堆栈 stack 中依次弹出 ‘com’、‘imooc’、‘www’
  • 此时堆栈 stack 的长度为 0

7. 访问集合

7.1 创建集合

>>> db.sadd('set', 'a')
1
>>> db.sadd('set', 'b')
1
>>> db.sadd('set', 'c')
1
  • 方法 sadd(set, value) 向集合 set 中添加元素 value
    • 如果集合 set 不存在,则创建一个集合
  • 在第 1 行,向集合 ‘set’ 添加元素 ‘a’
  • 在第 3 行,向集合 ‘set’ 添加元素 ‘b’
  • 在第 5 行,向集合 ‘set’ 添加元素 ‘c’

7.2 获取集合的成员

>>> db.scard('set')
3
>>> db.smembers('set')
{'b', 'c', 'a'}
  • 在第 1 行,使用方法 scard(‘set’) 获取集合的元素的数量
  • 在第 3 行,使用方法 smembers(‘set’) 获取集合的所有元素
>>> db.sismember('set', 'b')
True
>>> db.sismember('set', 'd')
False
  • 在第 1 行,使用方法 sismember(‘set’, ‘b’) 检查集合 ‘set’ 是否包含 ‘b’
  • 在第 3 行,使用方法 sismember(‘set’, ‘d’) 检查集合 ‘set’ 是否包含 ‘d’

7.3 求集合的交、并、差

>>> db.sadd('set2', 'b')
1
>>> db.sadd('set2', 'c')
1
>>> db.sadd('set2', 'd')
1
  • 创建集合 ‘set2’,向集合 ‘set2’ 中添加元素 ‘b’、‘c’、‘d’
>>> db.smembers('set')
{'a', 'b', 'c'}
>>> db.smembers('set2')
{'b', 'd', 'c'}
  • 显示集合 ‘set’ 与 集合 ‘set2’ 包含的成员
>>> db.sinter('set', 'set2')
{'b', 'c'}
>>> db.sunion('set', 'set2')
{'a', 'b', 'd', 'c'}
  • db.sinter(‘set’, ‘set2’) 求取集合的交集
  • db.sunion(‘set’, ‘set2’) 求取集合的并集
>>> db.sdiff('set', 'set2')
{'a'}
>>> db.sdiff('set2', 'set')
{'d'}
  • db.sdiff(‘set’, ‘set2’) 求取集合的差集
    • 在 ‘set’ 中出现,在 ‘set2’ 中没有出现的元素构成的集合
  • db.sdiff(‘set2’, ‘set’) 求取集合的差集
    • 在 ‘set2’ 中出现,在 ‘set’ 中没有出现的元素构成的集合

8. 访问哈希

8.1 创建哈希表

>>> db.hset('person', 'name', 'ZhangSan')
1
>>> db.hset('person', 'age', 20)
1
  • 方法 hset(hash_table, key, value),向哈希表 hash_table 增加一组键值对,键为 key、值为 value
    • 如果哈希表 hash_table 不存在,则创建一个新的哈希表
  • 创建一个哈希表 person,描述一个人,包括两项属性:name 和 age
  • 在第 1 行,为哈希表 person 增加一组键值对:键为 ‘name’、值为 ‘ZhangSan’
  • 在第 3 行,为哈希表 person 增加一组键值对:键为 ‘age’、值为 20
>>> db.hlen('person')
2
  • 方法 hlen(hash_table) 获取 hash_table 中键值对的数目

8.2 访问哈希表

>>> db.hget('person', 'name')
'ZhangSan'
>>> db.hget('person', 'age')
'20'
  • 方法 hget(hash_table, key) 获取哈希表 hash_table 中键为 key 对应的值
  • 在第 1 行,获取哈希表 ‘person’ 中键为 ‘name’ 的值
  • 在第 3 行,获取哈希表 ‘person’ 中键为 ‘age’ 的值
>>> db.hexists('person', 'name')
True
>>> db.hexists('person', 'gender')
False
  • 方法 hexists(hash_table, key) 返回哈希表 hash_table 是否包含键 key
  • 在第 1 行,获取哈希表 ‘person’ 是否包含 ‘name’
  • 在第 3 行,获取哈希表 ‘person’ 是否包含 ‘gender’

8.3 获取所有的键和值

>>> db.hkeys('person')
['name', 'age']
>>> db.hvals('person')
['ZhangSan', '20']
>>> db.hgetall('person')
{'name': 'ZhangSan', 'age': '20'}
  • 方法 hkeys(hash_table) 返回 hash_table 中所有的键
  • 方法 hvals(hash_table) 返回 hash_table 中所有的值
  • 方法 hgetall(hash_table) 返回一个字典,描述 hash_table 中所有的键和值

8.4 遍历哈希表

>>> keys = db.hkeys('person')
>>> for key in keys:
...     val = db.hget('person', key)
...     print('%s:%s' % (key, val))
...
name:ZhangSan
age:20
  • 在第 1 行,通过 hkeys() 方法获取所有的键
  • 在第 2 行,使用 for 循环遍历所有的键
  • 在第 3 行,使用 hget() 方法获取指定键对应的值
>>> dict = db.hgetall('person')
>>> for key,val in dict.items():
...     print('%s:%s' % (key, val))
...
name:ZhangSan
age:20
  • 在第 1 行,通过 hgetall() 方法获取所有的键值对,该方法返回一个字典
  • 遍历 hgetall() 返回的字典

8.5 增加键和删除键

>>> db.hset('person', 'gender', 'female')
1
>>> db.hgetall('person')
{'name': 'ZhangSan', 'age': '20', 'gender': 'female'}
>>> db.hdel('person', 'gender')
1
>>> db.hgetall('person')
{'name': 'ZhangSan', 'age': '20'}
  • 在第 1 行,为哈希表 ‘person’ 增加一个键 ‘gender’,值为 ‘female’
  • 在第 3 行,使用方法 hgetall(‘person’) 显示哈希表 ‘person’ 的键值对
    • 已经增加了一个键 ‘gender’
  • 在第 5 行,使用方法 hdel(‘person’, ‘gender’) 删除哈希表 ‘person’ 中的键 ‘gender’
  • 在第 7 行,使用方法 hgetall(‘person’) 显示哈希表 ‘person’ 的键值对
    • 已经删除了键 ‘gender’