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"))
解析: 设初始值,不指定amount 默认为1 ,上面最后输出 34636
 
应用场景 – 页面点击数
假定我们对一系列页面需要记录点击次数。
例如论坛的每个帖子都要记录点击次数,而点击次数比回帖的次数的多得多。如果使用关系数据库来存储点击,可能存在大量的行级锁争用。
所以,点击数的增加使用redis的INCR命令最好不过了。 
当redis服务器启动时,可以从关系数据库读入点击数的初始值(12306这个页面被访问了34634次)
 
10,incrbyfloat(self, name, amount=1.0)
 
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
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对应的有序集合的元素
参数:
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(pattern='')
更多:
KEYS * 匹配数据库中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS hllo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
4.设置超时时间
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"))
 
10,用户浏览信息缓存:
 
先把商品id保存
 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)


写了一天好累,部分 参考简书上:https://www.jianshu.com/p/2639549bedc8 ,更多详细信息,可以参考这个网址



01-12 00:58