redis连接
1,安装redis
pip install redis
实例:
import redis from datetime import datetime
r = redis.Redis(host='localhost', port=6379, db=15,decode_responses=True) r.set('name', 'lvye') print(r['name']) print(r.get('name')) print(type(r.get('name')))
lvye
lvye
<class 'str'>
decode_responses=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。
2、连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。
默认,每个Redis实例都会维护一个自己的连接池。
可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池
import 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对应的值
3,string redis基本命令
1,在Redis中设置值,默认,不存在则创建,存在则修改
set(name, value, ex=None, px=None, nx=False, xx=False)
参数:
- ex,过期时间(秒)
- px,过期时间(毫秒)
- nx,如果设置为True,则只有name不存在时,当前set操作才执行
- xx,如果设置为True,则只有name存在时,当前set操作才执行
2,setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)
print(r.setnx('fruit1', 'banana')) # fruit1不存在,输出为True
白话解释,不存在则直接创建新的,存在则返回false,不可以修改。
3,setex(name, value, time)
参数: time,期时间(数字秒 或 timedelta对象)
r.setex("fruit2", "orange", 5) time.sleep(5) print(r.get('fruit2')) # 5秒后,取值就从orange变成None
4.psetex(name, time_ms, value)
time_ms,过期时间(数字毫秒 或 timedelta对象)
r.psetex("fruit3", 5000, "apple") time.sleep(5) print(r.get('fruit3'))
5,批量设置值 mset(*args, **kwargs)
import redis r = redis.Redis(host='localhost', port=6379, db=15,decode_responses=True) r.mget({'k1': 'v1', 'k2': 'v2'}) r.mset(k1="v1", k2="v2") # 这里k1 和k2 不能带引号 一次设置对个键值对 print(r.mget("k1", "k2")) # 一次取出多个键对应的值 #['v1', 'v2'] print(r.mget("k1")) #['v1']
6,批量获取值,
print(r.mget('k1', 'k2')) print(r.mget(['k1', 'k2']))
7,设置新值并获取原来的值
r.set('name','yang')
s = r.getset('name','zhenyu')
print(s)
#yang
8,返回name对应值的字节长度(一个汉字3个字节)
s = r.strlen('name') print(s)
9,ncr(self, name, amount=1)
r.set("visit:12306:totals", 34634) r.incr("visit:12306:totals") r.incr("visit:12306:totals") print(r.get("visit:12306:totals"))
假定我们对一系列页面需要记录点击次数。
r.set("foo1", "123.0") r.set("foo2", "221.0") print(r.mget("foo1", "foo2")) r.incrbyfloat("foo1", amount=2.0) r.incrbyfloat("foo2", amount=3.0) print(r.mget("foo1", "foo2")) ['123.0', '221.0'] ['125', '224']
11,decr(self, name, amount=1)
自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
r.decr("foo5", amount=3) # 递减3 r.decr("foo6", amount=1) # 递减1 print(r.mget("foo5", "foo6")) #['-3', '-1']
12,append(key, value)
在redis name对应的值后面追加内容
r.append('name','yang') print(r.get('name'))
#zhenyuyang
4,hash redis基本命令
1.hset(name, key, value)
单个增加--修改(单个取出)--没有就新增,有的话就修改
r.hset("hash1", "k1", "v1")
r.hset("hash1", "k2", "v2")
print(r.hkeys("hash1")) # 取hash中所有的key
#['k1', 'k2']
print(r.hget("hash1", "k1")) # 单个取hash的key对应的值
# v1
print(r.hmget("hash1", "k1", "k2")) # 多个取hash的key对应的值
# ['v1', 'v2']
r.hsetnx("hash1", "k3", "v3") # 只能新建
print(r.hget("hash1", "k3"))
# 这个命令只能新建,不会覆盖原来的值
hget(name,key)
在name对应的hash中获取根据key获取value
hmget(name, keys, *args)
在name对应的hash中获取多个key的值
2,hmset(name, mapping)
批量插入数据,
参数:
name,redis的name
mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) print(r.hmget('hash2','k2','k3')) #['v2', 'v3']
3,hgetall(name)
获取所有的键值对
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) print(r.hgetall('hash2')) #{'k2': 'v2', 'k3': 'v3'}
4,hlen(name)
获取键值对长度,说白了就是计算几个字典而已
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) print(r.hgetall('hash2')) #{'k2': 'v2', 'k3': 'v3'} print(r.hlen('hash2')) #2
5,hkeys(name)
获取所有的键,返回列表
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) print(r.hkeys('hash2')) #['k2', 'k3']
6,hvals(name)
获取所有的值,返回列表
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) print(r.hvals('hash2')) #['v2', 'v3']
7,hexists(name, key)
判断成员是否存在(类似字典的in)
r.hmset("hash2", {"k2": "v2", "k3": "v3"}) s = r.hexists('hash2','k2') print(s) #True
8,hdel(name,*keys)
删除键值对
#{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} r.hdel("hash1", "k1") # 删除一个键值对 print(r.hgetall("hash1")) #{'k2': 'v222', 'k3': 'v3', 'k11': 'v1'}
9,hincrby(name, key, amount=1)
自增name对应的hash中的指定key的值,不存在则创建key=amount
r.hset("hash1", "k3", 123) r.hincrby("hash1", "k3", amount=-1) print(r.hgetall("hash1")) #{'k3': '122'} r.hincrby("hash1", "k4", amount=1) # 不存在的话,value默认就是1 print(r.hgetall("hash1")) #{'k3': '122', 'k4': '1'}
10,hincrbyfloat(name, key, amount=1.0)
自增自减浮点数(将key对应的value--浮点数 自增1.0或者2.0,或者别的浮点数 负数就是自减)
r.hset("hash1", "k5", "1.0") r.hincrbyfloat("hash1", "k5", amount=-1.0) # 已经存在,递减-1.0 print(r.hgetall("hash1")) #{'k5': '0'} r.hincrbyfloat("hash1", "k6", amount=-1.0) # 不存在,value初始值是-1.0 每次递减1.0 print(r.hgetall("hash1")) #{'k5': '0', 'k6': '-1'}
11,hscan_iter(name, match=None, count=None)
利用yield封装hscan创建生成器,实现分批去redis中获取数据
参数:
match,匹配指定key,默认None 表示所有的key
count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
print(r.hgetall('hash1')) #{'k5': '0', 'k6': '-1'} for item in r.hscan_iter('hash1'): print(item) #('k5', '0') #('k6', '-1') #f返回键值对元祖
5,list redis基本命令
1,lpush(name,values)
增加(类似于list的append,只是这里是从左边新增加)--没有就新建
r = redis.Redis(host='localhost', port=6379, db=15,decode_responses=True) r.lpush("list1", 11, 22, 33) print(r.lrange('list1', 0, -1)) #['33', '22', '11']
扩展:
r.rpush("list2", 11, 22, 33) # 表示从右向左操作 print(r.llen("list2")) # 列表长度 print(r.lrange("list2", 0, 3)) # 切片取出值,范围是索引号0-3
2,lpushx(name,value)
往已经有的name的列表的左边添加元素,没有的话无法创建
r.lpushx("list1", 11) #该list1必须存在,否则无法插入
3,rpushx(name,value)
往已经有的name的列表的右边添加元素,没有的话无法创建
print(r.lrange('list1',0,-1)) #['1100', '11', '33', '22', '11', '33', '22', '11', '1100'] r.rpushx("list1", 1100) #增加 print(r.lrange('list1',0,-1)) #['1100', '11', '33', '22', '11', '33', '22', '11', '1100', '1100']
4,linsert(name, where, refvalue, value))
在name对应的列表的某一个值前或后插入一个新值
参数:
name,redis的name
where,BEFORE或AFTER
refvalue,标杆值,即:在它前后插入数据
value,要插入的数据
r.linsert("list1", "before", "11", "00") #意思是在11 之前插入00
5,r.lset(name, index, value)
对name对应的list中的某一个索引位置重新赋值
参数:
name,redis的name
index,list的索引位置
value,要设置的值
print(r.lrange('list1',0,-1)) #['1100', '00', '11', '33', '22', '11', '33', '22', '11', '1100', '1100'] r.lset('list1',1,'222') #对下标1的值改为222 print(r.lrange('list1',0,-1)) #['1100', '222', '11', '33', '22', '11', '33', '22', '11', '1100', '1100']
6,r.lrem(name, value, num)
在name对应的list中删除指定的值
参数:
name,redis的name
value,要删除的值
num,
num=0,删除列表中所有的指定值;
num=2,从前到后,删除2个; num=1,从前到后,删除左边第1个
num=-2,从后向前,删除2个
print(r.lrange("list1", 0, -1)) #['1100', '222', '11', '33', '22', '11', '33', '22', '11', '1100', '1100'] r.lrem('list1','1100',4) #左边出现的11,后面指定删除数量 print(r.lrange("list1", 0, -1)) #['1100', '222', '33', '22', '11', '33', '22', '11', '1100', '1100']
7,lpop(name)
在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
s = r.lpop('list1') #从左边删除第一个,并返回
s = r.rpop('list1') #从右边删除第一个,并返回
8,ltrim(name, start, end)
在name对应的列表中移除没有在start-end索引之间的值
参数:
name,redis的name
start,索引的起始位置
end,索引结束位置
print(r.lrange("list1", 0, -1)) #['33', '22', '11', '22', '33', '22'] r.ltrim('list1',0,2) #下标0-2也就是3个数,不在这个范围的删除 print(r.lrange("list1", 0, -1)) #['33', '22', '11']
9,lindex(name, index)
在name对应的列表中根据索引获取列表元素
print(r.lrange("list1", 0, -1)) #['33', '22', '11'] print(r.lindex('list1',0)) #33
10,rpoplpush(src, dst)
移动 元素从一个列表移动到另外一个列表
# list1 ['33', '22'] # list2 ['11', '5', '4', '3', '2', '1']
r.rpoplpush('list1','list2') #可以看出从第一个列表最右边一个移到第二个列表的最左侧 print(r.lrange("list1", 0, -1)) print(r.lrange("list2", 0, -1)) #['33'] #['22', '11', '5', '4', '3', '2', '1']
11,brpoplpush(src, dst, timeout=0)
移动 元素从一个列表移动到另外一个列表 可以设置超时
参数:
src,取出并要移除元素的列表对应的name
dst,要插入元素的列表对应的name
timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
r.brpoplpush('list1','list2' , timeout=0) print(r.lrange("list1", 0, -1)) print(r.lrange("list2", 0, -1)) #['33']
6,set redis基本命令
1,sadd(name,values)
name对应的集合中添加元素
r.sadd("set1", 33, 44, 55, 66) # 往集合中添加元素 print(r.scard("set1")) # 集合的长度是4 print(r.smembers("set1")) # 获取集合中所有的成员 #{'33', '55', '44', '66'}
2.获取元素个数 类似于 len
scard(name)
获取 name 对应的集合中元素个数
3.获取集合中所有的成员
smembers(name)
获取name对应的集合的所有成员
4, sscan('set1')
获取集合中所有的成员--元组形式
r.sadd("set1", 33, 44, 55, 66) # 往集合中添加元素 print(r.sscan('set1')) #(0, ['33', '44', '55', '66'])
5,sscan_iter()
获取集合中所有的成员--迭代器的方式
for i in r.sscan_iter('set1'): print(i) ''' 33 44 55 66 '''
6,sismember(name, value)
判断是否是集合的成员 类似in
print(r.smembers("set2")) #{'55', '33', '66', '44'} print(r.sismember('set2', '33'))
True
7,smove(src, dst, value)
将某个成员从一个集合中移动到另外一个集合
print(r.smembers("set2")) #{'55', '66', '33', '44'} print(r.smembers("set3")) #{'11', '22', '33'} r.smove("set2", "set3", '44') #移动 print(r.smembers("set2")) #{'66', '55', '33'} print(r.smembers("set3")) #{'44', '11', '22', '33'}
8,spop(name)
从集合移除一个成员,并将其返回,说明一下,集合是无序的,所有是随机删除的
print(r.smembers("set2")) s = r.spop('set2') print(s) print(r.smembers("set2")) ''' {'66', '55', '33'} 66 {'55', '33'} '''
’8,srem(name, values)
删除--指定值删除
print(r.smembers("set2")) r.srem('set2','55') print(r.smembers("set2")) ''' {'33', '55'} {'33'} '''
7,redis基本命令 有序set
- Set操作,Set集合就是不允许重复的列表,本身是无序的
- 有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,
- 所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
1,zadd()
向有序集合添加元素
r.zadd("zset1", n1=11, n2=22) r.zadd("zset2", 'm1', 22, 'm2', 44) print(r.zcard("zset1")) # 集合长度 print(r.zcard("zset2")) # 集合长度 print(r.zrange("zset1", 0, -1)) # 获取有序集合中所有元素 print(r.zrange("zset2", 0, -1, withscores=True)) # 获取有序集合中所有元素和分数 2 2 ['n1', 'n2'] [('m1', 22.0), ('m2', 44.0)]
2.获取有序集合元素个数 类似于len
zcard(name)
print(r.zcard("zset1")) # 集合长度
获取name对应的有序集合元素的数量
3.r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
参数:
name,redis的name start,有序集合索引起始位置(非分数) end,有序集合索引结束位置(非分数) desc,排序规则,默认按照分数从小到大排序 withscores,是否获取元素的分数,默认只获取元素的值 score_cast_func,对分数进行数据转换的函数
4,zrevrange(name, start, end, withscores=False, score_cast_func=float)
同zrange,集合是从大到小排序的
r.zadd("zset1", n1=11, n2=22)
print(r.zrevrange("zset1", 0, -1)) # 只获取元素,不显示分数 print(r.zrevrange("zset1", 0, -1, withscores=True)) # 获取有序集合中所有元素和分数,分数倒序 ''' ['n2', 'n1'] [('n2', 22.0), ('n1', 11.0)] '''
5,zscan_iter(name, match=None, count=None,score_cast_func=float)
获取所有元素--迭代器
r.zadd("zset1", n1=11, n2=22) for i in r.zscan_iter("zset1"): # 遍历迭代器 print(i) ''' ('n1', 11.0) ('n2', 22.0) '''
6,zcount(name, min, max)
获取name对应的有序集合中分数 在 [min,max] 之间的个数
r.zadd("zset1", n1=11, n2=22) print(r.zrange("zset1", 0, -1, withscores=True)) print(r.zcount("zset1", 11, 22)) ''' [('n1', 11.0), ('n2', 22.0)] 2 '''
7,自增name对应的有序集合的 name 对应的分数
zincrby(name, value, amount)
r.zadd("zset1", n1=11, n2=22) r.zincrby("zset1", "n2", amount=2) # 每次将n2的分数自增2 print(r.zrange("zset1", 0, -1, withscores=True))
#[('n1', 11.0), ('n2', 24.0)]
8,zrank(name, value)
获取值的索引号
r.zadd("zset1", n1=11, n2=22) print(r.zrank("zset1", "n1")) # n1的索引号是0 这里按照分数顺序(从小到大) #0 print(r.zrank("zset1", "n2")) # n2的索引号是1 #1 print(r.zrevrank("zset1", "n1")) # n1的索引号是1 这里安照分数倒序(从大到小) #1
9,zrem(name, values)
删除name对应的有序集合中值是values的成员
r.zadd("zset1", n1=11, n2=22) r.zrem("zset1", "n1") # 删除有序集合中的元素n1 删除单个 print(r.zrange("zset1", 0, -1)) #['n2']
10,zremrangebyrank(name, min, max)
删除--根据排行范围删除,按照索引号来删除
r.zadd("zset1", n1=11, n2=22,n3=33,n4=55) r.zremrangebyrank('zset1',0,2) #删除这个区间的元素,包括2 print(r.zrange("zset1", 0, -1)) #['n4']
11,zremrangebyscore(name, min, max)
根据分数范围删除
r.zadd("zset1", n1=11, n2=22,n3=33,n4=55) r.zremrangebyscore('zset1',0,22) #删除这个区间的分数,包括22 print(r.zrange("zset1", 0, -1)) #['n3', 'n4']
12,zscore(name, value)
获取值对应的分数
r.zadd("zset1", n1=11, n2=22,n3=33,n4=55) print(r.zscore('zset1', 'n1')) #11.0
8、其他常用操作
1.删除
delete(*names)
根据删除redis中的任意数据类型(string、hash、list、set、有序set)
r.delete("list2") # 删除key为gender的键值对
2.检查名字是否存在
exists(name)
检测redis的name是否存在,存在就是True,False 不存在
print(r.exists('set1'))
3.模糊匹配
KEYS * 匹配数据库中所有 key 。 KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 KEYS hllo 匹配 hllo 和 heeeeello 等。 KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
expire(name ,time)
为某个redis的某个name设置超时时间
r.lpush("list5", 11, 22) r.expire("list5", time=3) print(r.lrange("list5", 0, -1)) time.sleep(3) print(r.lrange("list5", 0, -1))
5.重命名
rename(src, dst)
对redis的name重命名
r.lpush("list5", 11, 22) r.rename("list5", "list5-1")
6.随机获取name
randomkey()
随机获取一个redis的name(不删除)
print(r.randomkey())
7.获取类型
type(name)
获取name对应值的类型
print(r.type("set1")) print(r.type("hash2"))
8.查看所有元素
scan(cursor=0, match=None, count=None)
print(r.hscan("hash2")) print(r.sscan("set3")) print(r.zscan("zset2")) print(r.getrange("foo1", 0, -1)) print(r.lrange("list2", 0, -1)) print(r.smembers("set3")) print(r.zrange("zset3", 0, -1)) print(r.hgetall("hash1"))
9.查看所有元素--迭代器
scan_iter(match=None, count=None)
for i in r.hscan_iter("hash1"): print(i) for i in r.sscan_iter("set3"): print(i) for i in r.zscan_iter("zset3"): print(i)
other 方法
print(r.get('name')) # 查询key为name的值 r.delete("gender") # 删除key为gender的键值对 print(r.keys()) # 查询所有的Key print(r.dbsize()) # 当前redis包含多少条数据 r.save() # 执行"检查点"操作,将数据写回磁盘。保存时阻塞 # r.flushdb() # 清空r中的所有数据
9,管道(pipeline)
redis默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,
如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。
管道(pipeline)是redis在提供单个请求中缓冲多条服务器命令的基类的子类。它通过减少服务器-客户端之间反复的TCP数据库包,从而大大提高了执行批量命令的功能。
import redis import time pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) r = redis.Redis(connection_pool=pool) # pipe = r.pipeline(transaction=False) # 默认的情况下,管道里执行的命令可以保证执行的原子性,执行pipe = r.pipeline(transaction=False)可以禁用这一特性。 # pipe = r.pipeline(transaction=True) pipe = r.pipeline() # 创建一个管道 pipe.set('name', 'jack') pipe.set('role', 'sb') pipe.sadd('faz', 'baz') pipe.incr('num') # 如果num不存在则vaule为1,如果存在,则value自增1 pipe.execute() print(r.get("name")) print(r.get("role")) print(r.get("num"))
管道的命令可以写在一起,如:
pipe.set('hello', 'redis').sadd('faz', 'baz').incr('num').execute() print(r.get("name")) print(r.get("role")) print(r.get("num"))
conn = get_redis_connection('history') # 2、判断goodid是否保存过,保存过删除 conn.lrem('history_%s' % user.id, 0, validated_data['goodid']) # 3、写入goodid conn.lpush('history_%s' % user.id, validated_data['goodid']) # 4、控制保存数量 conn.ltrim('history_%s' % user.id, 0, 4)
然后redis里取出来
# 1、获取用户对象 user = request.user # 2、查询redis获取goodid conn = get_redis_connection('history') goodlists = conn.lrange('history_%s' % user.id, 0, 5) # [3,1,2] # 3、根据sku_id查询商品对象 goods = GoodInfo.objects.filter(id__in=goodlists) # 4、序列化返回商品信息 ser =self.get_serializer(goods,many=True)