使用python操作Redis

安装

1
pip install redis

简单使用

1
2
3
4
5
6
7
8
from redis import Redis
# 实例化,创建连接
conn = Redis("127.0.0.1",6379,)
# 设置key
conn.set("key1","123")
# 取值
ret = conn.get("key1")
print(ret)

使用连接池

1
2
3
4
5
6
7
import redis
# 创建redis连接池
pool = redis.ConnectionPool(host="127.0.0.1",port=6379,max_connections=100)
# 从池中获取一个连接
conn = redis.Redis(connection_pool=pool)
ret = conn.get("key1")
print(ret)

1 String方法

在内存中按照一个name对应一个value来存储。

set

存储一条数据。

1
def set(self, name, value, ex=None, px=None, nx=False, xx=False, keepttl=False)

参数:

  • name:键
  • value:值
  • ex:过期时间(秒)
  • px:过期时间(毫秒)
  • nx:如果为True,只有name不存在时,当前set操作才执行。值存在,就修改不了,执行没效果
  • xx:如果为True,只有name存在时,当前set操作才执行。值存在才能修改,值不存在,不会设置新值
  • keepttl:如果为True,保留之前给这个key设置的过期时间(redis6.0版本新增)

与之相关的命令:

**setnx(name, value)**:相当于set默认将nx参数设为True

**setex(name, value, time)**:相当于set必须传一个过期时间(秒)

**psetex(name, time_ms, value)**:相当于set必须传一个过期时间(毫秒)

mset

批量存储。

1
def mset(self, mapping)

参数:

  • mapping:传入一个字典。字典内的键值必须是字符串格式,或者能够被str()方法转成字符串

get

根据name获取单个值。

1
def get(self, name)

参数:

  • name:键

mget

批量获取值。

1
def mget(self, keys, *args)

支持批量传入

1
2
3
4
# 举例
# 推荐传入包含key的列表
ret = conn.mget("key1","key2","key3")
ret = conn.mget(["key1","key2","key3"])

getset

获取原来的值,并传入新值。

1
def getset(self, name, value)

参数:

  • name:键
  • value:值

getrange

按字节划定区间,取子串。

1
def getrange(self, key, start, end)

参数:

  • key:键
  • start:起始位置
  • end:终止位置
1
2
3
# 举例
ret = conn.getrange("key1",0,1)
# 闭区间,即区间[0,1],单位是字节(不是字符)

setrange

修改字符串内容,从起始位置开始向后替换(超出原有长度则增加)

1
def setrange(self, name, offset, value)

参数:

  • name:键
  • offset:起始位置(从0开始,按字节,1汉字为3字节)
  • value:要设置的值

strlen

返回name对应值得长度(字节为单位)

1
def strlen(self, name)

setbit、getbit、bitcount、bitop

比特操作,不常用。

incr

将name对应的值增加amount;如果name对应为空,则将它初始化为amount

1
def incr(self, name, amount=1)

默认每执行一次,就自增1

amount可以设置为负数,实现decr相同功能。

incrbyfloat

将name对应的值增加amount;如果name对应为空,则将它初始化为amount(浮点型)

1
def incrbyfloat(self, name, amount=1.0)

decr

与incr对应,自减。

1
def decr(self, name, amount=1)

append

在key对应的值后面追加value

1
def append(self, key, value):

2 Hash方法

在内存中按照一个name对应一个字典来存储

image

hset

name对应的hash中设置一个键值对(不存在,则创建;存在,则修改)

1
def hset(self, name, key=None, value=None, mapping=None):

参数:

  • mapping:接受一个字典,可以传入多个值。(**貌似python3.8以后支持)
1
conn.hset("name","k1","v1",{"k2":"v2","k3":"v3"})

hmset

在name对应的hash中批量设置

举例:

1
ret = conn.hmset(name="name",mapping={"k2":"v2","k3":"v3"})

hget

获取name中的key对应的值

1
def hget(self, name, key)

hmget

批量获取

1
def hmget(self, name, keys, *args)

参数:

  • keys:要获取key集合,如:[‘k1’, ‘k2’, ‘k3’]
  • args:要获取的key,如:k1,k2,k3

举例:

1
2
3
# 两种方式都可以
conn.hmget("name",['k1', 'k2', 'k3'])
conn.hmget("name",'k1', 'k2', 'k3')

hgetall

获取name对应hash的所有键值

1
def hgetall(self, name)

hlen

获取name对应的hash中键值对的个数

1
def hlen(self, name)

hkeys、hvals

获取name对应的所有key或者value值得

1
2
def hkeys(self, name)
def hvals(self, name)

hexists

检查name对应的hash是否存在当前传入的key

1
def hexists(self, name, key)

存在返回True,不存在返回False

hdel

将name对应的hash中指定key的键值对删除

1
def hdel(self, name, *keys)

keys可以是列表传入多个

hincrby

自增name对应的hash中的指定key的值,不存在则创建key=amount

1
def hincrby(self, name, key, amount=1)

hincrbyfloat

浮点型自增,其他同上

1
def hincrbyfloat(self, name, key, amount=1.0)

hscan

增量式迭代获取。对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完。

1
def hscan(self, name, cursor=0, match=None, count=None)

参数:

  • name:键
  • cursor:游标(默认从0开始)基于游标获取数据
  • match:匹配指定key,默认None 表示所有的key
  • count:每次分片最少获取个数,默认None表示采用Redis的默认分片个数

举例:

1
2
3
4
# 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
# 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
# ...
# 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕

hscan_iter

利用yield封装hscan创建生成器,实现分批去redis中获取数据

1
def hscan_iter(self, name, match=None, count=None)

参数:

  • name:键
  • match:匹配指定key,默认None 表示所有的key
  • count:每次分片最少获取个数,默认None表示采用Redis的默认分片个数

举例:

1
2
for item in conn.hscan_iter('xx'):
print item

==如果想取回所有数据,不建议使用hgetall,建议使用hscan_iter==

3 List方法

在内存中按照一个name对应一个列表来存储。

image

lpush、rpush

在name对应的list中添加元素,每个新的元素都添加到列表的最左边或者最右边

1
2
def lpush(self, name, *values)
def rpush(self, name, *values):

举例:

1
2
3
4
5
r.lpush('name', 11,22,33)
# 保存顺序为: 33,22,11

r.rpush('name', 11,22,33)
# 保存顺序为: 11,22,33,

lpushx、rpushx

在name对应的list中添加元素,只有name存在时,每个新的元素会添加到列表的最左边或者最右边

1
2
def rpush(self, name, *values)
def rpushx(self, name, value)

lpop、rpop

在name对应的列表的左侧或者右侧获取第一个元素并在列表中移除,返回值则是第一个元素

1
2
def lpop(self, name)
def rpop(self, name)

linsert

在name对应的列表的某一个值前或后插入一个新值

1
def linsert(self, name, where, refvalue, value)

参数:

  • name:键
  • where:BEFORE或AFTER(小写也可以)
  • refvalue:参考值。在它的前后插入数据(如果存在多个,以找到的第一个为准)
  • value:要插入的值

lset

对name对应的list中的某一个索引位置重新赋值

1
def lset(self, name, index, value)

参数:

  • name:键
  • index:list的索引位置
  • value:要设置的值

lrem

在name对应的list中删除指定的值

1
def lrem(self, name, count, value)

参数:

  • name:键

  • count

    1
    2
    3
    count > 0: 从头到尾删除count个value
    count < 0: 从尾到头删除count个value
    count = 0: 删除所有value
  • value:要删除的值

lindex

在name对应的列表中根据索引获取列表元素

1
def lindex(self, name, index)

lrange

在name对应的列表分片获取数据,从start到end

1
def lrange(self, name, start, end)

参数:

  • name:值
  • start:索引的起始位置,可以是负数
  • end:索引结束位置,可以是负数

ltrim

在name对应的列表中移除没有在start-end索引之间的值,闭区间

1
ltrim(self, name, start, end)

参数:

  • name:值
  • start:索引的起始位置,可以是负数
  • end:索引结束位置,可以是负数(大于列表长度,则代表不移除任何)

rpoplpush

从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边

1
def rpoplpush(self, src, dst)

参数:

  • src:要取数据的列表的name
  • dst:要添加数据的列表的name

blpop、brpop

b表示阻塞,将多个列表排列,按照从左到右去pop对应列表的元素(l);按照从右到左去pop对应列表的元素(r)

1
2
def blpop(self, keys, timeout=0)
def brpop(self, keys, timeout=0)

参数:

  • keys:所有的name
  • timeout:超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞

应用场景:

1
# 爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式

brpoplpush

从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧

1
def brpoplpush(self, src, dst, timeout=0)

参数:

  • src:取出要移除元素的列表对应的name
  • dst:要插入元素的列表对应的name
  • timeout:超时时间,当src对应列表中没有数据时,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞

自定义增量迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
# 1、获取name对应的所有列表
# 2、循环列表
# 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:
import redis
conn=redis.Redis(host='127.0.0.1',port=6379)
# conn.lpush('test',*[1,2,3,4,45,5,6,7,7,8,43,5,6,768,89,9,65,4,23,54,6757,8,68])
# conn.flushall()
def scan_list(name,count=2):
index=0
while True:
data_list=conn.lrange(name,index,count+index-1)
if not data_list:
return
index+=count
for item in data_list:
yield item
print(conn.lrange('test',0,100))
for item in scan_list('test',5):
print('---')
print(item)

4 set方法

Set集合就是不允许重复的列表。

sadd

name对应的集合中添加元素

1
def sadd(self, name, *values)

scard

获取name对应的集合中元素个数

1
def scard(self, name)

sdiff

返回一个集合,该集合石传入集合之间的差集。

1
def sdiff(self, keys, *args):

sdiffstore

返回一个集合,该集合石传入集合之间的差集。把这个集合存储到新dest的集合中

1
def sdiffstore(self, dest, keys, *args)

sinter

返回一个集合,该集合石传入集合之间的交集。

1
def sinter(self, keys, *args)

sinterstore

返回一个集合,该集合石传入集合之间的交集。把这个集合存储到新dest的集合中

1
def sinterstore(self, dest, keys, *args)

sismember

检查value是否是name对应的集合的成员

1
def sismember(self, name, value)

smembers

返回集合name中的所有成员。

1
def smembers(self, name)

smove

将某个成员从一个集合中移动到另外一个集合

将value从src移动到dst

1
def smove(self, src, dst, value)

spop

从集合的右侧(尾部)移除count个成员name,并将其返回

1
def spop(self, name, count=None)

srandmember

从name对应的集合中随机获取number个元素

如果number不指定,就随即返回一个;如果指定,且小于集合长度,则返回指定的个数;如果大于集合长度,就返回整个集合。

1
def srandmember(self, name, number=None)

srem

在name对应的集合中删除某些值

1
def srem(self, name, *values)

sunion

获取keys指定的所有集合的并集

1
def sunion(self, keys, *args)

sunionstore

返回一个集合,该集合石传入集合之间的并集。把这个集合存储到新dest的集合中

1
def sunionstore(self, dest, keys, *args)

5 SortedSet方法

SortedSet就是有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

zadd

1
def zadd(self, name, mapping, nx=False, xx=False, ch=False, incr=False)

zcard

1
def zcard(self, name):

zcount

1
def zcount(self, name, min, max):

zincrby

1
def zincrby(self, name, amount, value):

zrange

1
def zrange(self, name, start, end, desc=False, withscores=False,score_cast_func=float):

zrank

1
def zrank(self, name, value):

zrangebylex

1
def zremrangebylex(self, name, min, max):

zrem

1
def zrem(self, name, *values):

zremrangebyrank

1
def zremrangebyrank(self, name, min, max):

zremrangebyscore

1
def zremrangebyscore(self, name, min, max):

zremrangebylex

1
def zremrangebylex(self, name, min, max):

zscore

1
def zscore(self, name, value):

zinterstore

1
def zinterstore(self, dest, keys, aggregate=None):

zunionstore

1
def zunionstore(self, dest, keys, aggregate=None):

zscan

1
def zscan(self, name, cursor=0, match=None, count=None,score_cast_func=float):

zscan_iter

1
def zscan_iter(self, name, match=None, count=None,score_cast_func=float):

6 其他方法

delete

删除给定的一个或多个键,不存在的会被忽略

1
def delete(self, *names)

exists

检查给定的键是否存在

1
def exists(self, *names)

keys

获取符合匹配条件的所有keys

1
2
3
4
5
def keys(self, pattern='*'):
# KEYS * 匹配数据库中所有 key 。
# KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
# KEYS h*llo 匹配 hllo 和 heeeeello 等。
# KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替

expire

为给定name设置生存时间,当name过期时(生存时间为 0 ),它会被自动删除。time为时间(单位秒)

1
def expire(self, name, time):

rename

重命名key。将src重命名为dst

1
def rename(self, src, dst):

move

将某个值移动到指定的db下

1
def move(self, name, db):

randomkey

随机获取一个name(不删除)

1
def randomkey(self):

type

获取name对应值的类型

1
def type(self, name):

scan

增量迭代获取,与zscan和hscan同理

1
def scan(self, cursor=0, match=None, count=None, _type=None):

scan_iter

利用yield封装scan创建生成器,实现分批去redis中获取数据

1
def scan_iter(self, match=None, count=None, _type=None):

7 管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline是原子性操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
import redis

pool = redis.ConnectionPool(host='10.211.55.4', port=6379)

r = redis.Redis(connection_pool=pool)

# pipe = r.pipeline(transaction=False)
pipe = r.pipeline(transaction=True) # transaction=true 开启事务
pipe.multi() # 标记着事物的开启
pipe.set('name', 'xxx')
pipe.set('age', '18')

pipe.execute() # 只有到这里才执行,执行完事物结束

有关更多操作,查看中文文档

8 Django中使用redis

方式一:

utils文件夹下,建立redis_pool.py

1
2
import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,password='1234',max_connections=1000)

视图函数中使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import redis
from django.shortcuts import render,HttpResponse
from utils.redis_pool import POOL

def index(request):
conn = redis.Redis(connection_pool=POOL)
conn.hset('kkk','age',18)

return HttpResponse('设置成功')
def order(request):
conn = redis.Redis(connection_pool=POOL)
conn.hget('kkk','age')

return HttpResponse('获取成功')

方式二:

安装django-redis模块官方github

1
pip3 install django-redis

setting里配置:

1
2
3
4
5
6
7
8
9
10
11
12
# redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}
# "PASSWORD": "123",
}
}
}

视图函数:

1
2
3
from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))