【luffy】redis操作和celery介绍
目录
1. 安装图形化客户端redis-desktop-manage
qt5: Qt是诺基亚公司的C++可视化开发平台,最新版本为Qt 5
QT平台:可以写图形化界面
python:pyqt5写图形化界面 GUI开发
到官网下载安装,一路下一步


2. redio 字符串操作
# 主要的api:操作字符串的方法
'''
1 set(name, value, ex=None, px=None, nx=False, xx=False)
2 setnx(name, value)
3 psetex(name, time_ms, value)
4 mset(*args, **kwargs)
4 get(name)
5 mget(keys, *args)
6 getset(name, value)
7 getrange(key, start, end)
8 setrange(name, offset, value)
9 setbit(name, offset, value)
10 getbit(name, offset)
11 bitcount(key, start=None, end=None)
12 strlen(name)
13 incr(self, name, amount=1)
14 incrbyfloat(self, name, amount=1.0)
15 decr(self, name, amount=1)
16 append(key, value)
'''
import redis
conn = redis.Redis()
# 1. set(name, value, ex=None, px=None, nx=False, xx=False)
# 在Redis中设置值,默认,不存在则创建,存在则修改
# 参数:
# ex,过期时间(秒)
# px,过期时间(毫秒)
# nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
# xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
# conn.set('name', 'zhy') # vallue 只能是字符串或byte格式
# conn.set('name', [1,123]) # Invalid input of type: 'list'. Convert to a bytes, string, int or float first.
# conn.set('name', 'zhy', ex=2) # ex是过期时间,到2秒触发,数据就没了
# conn.set('name', 'zhy', px=2000) # ex是过期时间,到2秒触发,数据就没了
# conn.set('age', 18, nx=True) # redis 实现分布式锁:https://zhuanlan.zhihu.com/p/489305763
# conn.set('name', 'zzz', xx=True)
# 2 setnx(name, value) # 就是set nx=True
# conn.setnx('hobby','足球')
# 3 psetex(name, time_ms, value) # 本质就是 set px设置时间
# conn.psetex('name', 2000, 'zzz')
# 4 mset(*args, **kwargs) # 传字典批量设置
# conn.mset({'name': 'zzz', 'age': 18})
# 5 get(name) # 获取值,取到是bytes格式 ,指定:decode_responses=True,就完成转换
# print(conn.get('name')) # b'zzz'
# print(str(conn.get('name')[:2], encoding='utf-8')) # zz
# 6 mget(keys, *args) # 批量获取
# res = conn.mget('name','age') # [b'zzz', b'18']
# res1 = conn.mget(['name','age']) # [b'zzz', b'18']
# print(res)
# print(res1)
# 7 getset(name, value) # 先获取,在设置
# res = conn.getset('name', 'zhy')
# print(res) # b'zzz'
# 8 getrange(key, start, end) # 取的是字节,前闭后闭区间
# res = conn.getrange('name', 0, 1)
# print(res) # b'zh'
# 9 setrange(name, offset, value) # 从某个起始位置开始替换字符串
# conn.setrange('name', 1, 'zzz') # 'zhy'-->'zzzz'
# 10 setbit(name, offset, value)
# conn.setbit('name', 1, 0)
# res = conn.get('name')
# print(res) # b':zzz'
# conn.setbit('name', 0, 1)
# res1 = conn.get('name')
# print(res1) # b'\xbazzz'
# 11 getbit(name, offset)
# res = conn.getbit('name', 1)
# print(res) # 0
# 12 bitcount(key, start=None, end=None)
# print(conn.bitcount('name', 0, 3)) # 3 指的是3个字符 15
# 13 strlen(name)
# print(conn.strlen('name')) # 3 # 统计字节长度
# print(len('zzz在')) # 4 # len 统计字符长度
# 14 incr(self, name, amount=1) # 计数器
# res = conn.incr('age',amount=3)
# print(res) # 21-->24
# 15 incrbyfloat(self, name, amount=1.0) # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# conn.incrbyfloat('money', amount=1.0)
# 16 decr(self, name, amount=1) # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# print(conn.decr('age')) # 24-->23
# 17 append(key, value)
conn.append('name', 'zx') # zzz-->zzzzx
conn.close()
3. redis hash操作
'''
1 hset(name, key, value)
2 hmset(name, mapping)
3 hget(name,key)
4 hmget(name, keys, *args)
5 hgetall(name)
6 hlen(name)
7 hkeys(name)
8 hvals(name)
9 hexists(name, key)
10 hdel(name,*keys)
11 hincrby(name, key, amount=1)
12 hincrbyfloat(name, key, amount=1.0)
13 hscan(name, cursor=0, match=None, count=None)
14 hscan_iter(name, match=None, count=None)
记住:hset hget hexists hincrby hlen
'''
import redis
conn = redis.Redis()
# 1 hset(name, key, value) name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
# conn.hset('user', 'name', '胡歌')
# conn.hset('user', 'age', '18')
# conn.hset('aa', mapping={'name': 'zzz', 'hobby': '篮球'})
# 2 hmset(name, mapping) 在name对应的hash中批量设置键值对
# conn.hmset('bb',{'a':'a','b':'b'})
# 3 hget(name,key) 在name对应的hash中获取根据key获取value
# print(conn.hget('user', 'age')) # b'18'
# 4 hmget(name, keys, *args) 在name对应的hash中获取多个key的值
# print(conn.hmget('user',['name','age'])) # [b'\xe8\x83\xa1\xe6\xad\x8c', b'18']
# 5 hgetall(name) 获取name对应hash的所有键值 慎用,可能会造成 阻塞 尽量不要在生产代码中执行它
# print(conn.hgetall('user')) # {b'name': b'\xe8\x83\xa1\xe6\xad\x8c', b'age': b'18'}
# 6 hlen(name) 获取name对应的hash中键值对的个数
# print(conn.hlen('user')) # 2
# 7 hkeys(name) 获取name对应的hash中所有的key的值
# print(conn.hkeys('user')) # [b'name', b'age']
# 8 hvals(name) 获取name对应的hash中所有的value的值
# print(conn.hvals('user')) # [b'\xe8\x83\xa1\xe6\xad\x8c', b'18']
# 9 hexists(name, key) 检查name对应的hash是否存在当前传入的key
# print(conn.hexists('user','name')) # Turn
# 10 hdel(name,*keys) 将name对应的hash中指定key的键值对删除
# print(conn.hexists('user','age')) # Turn
# 11 hincrby(name, key, amount=1) 自增name对应的hash中的指定key的值,不存在则创建key=amount
# conn.hincrby('user','age') # 18--19
# 12 hincrbyfloat(name, key, amount=1.0) 自增name对应的hash中的指定key的值,不存在则创建key=amount
# conn.hincrbyfloat('user','age') # 19--20
# 13 hscan(name, cursor=0, match=None, count=None) 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
# hash类型没有顺序 - --》python字典之前没有顺序,3.6后有序了python字段的底层实现
# for i in range(1000):
# conn.hset('test_hash', 'key_%s' % i, '鸡蛋%s号' % i)
# count 是要取的条数,但是不准确,有点上下浮动
# 它一般步单独用
# res = conn.hscan('test_hash',cursor=0,count=10)
# print(res)
# print(res[0])
# print(res[1])
# print(len(res[1])) # 10 ,9
# res=conn.hscan('test_hash',cursor=res[0],count=10)
# print(res)
# print(res[0])
# print(res[1])
# print(len(res[1]))
# 14 hscan_iter(name, match=None, count=None) 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 它内部封装了hscan,做成了生成器,分批取hash类型所有数据
res = conn.hscan_iter('test_hash',count=10)
print(res) # <generator object ScanCommands.hscan_iter at 0x0000021208A472E0> 生成器
# for item in res:
# print(item)
conn.close()
4. redis列表操作
'''
1 lpush(name,values)
2 lpushx(name,value)
3 rpushx(name, value) 表示从右向左操作
4 llen(name)
5 linsert(name, where, refvalue, value))
6 lset(name, index, value)
7 lrem(name, value, num)
8 lpop(name)
9 lindex(name, index)
10 lrange(name, start, end)
11 ltrim(name, start, end)
12 rpoplpush(src, dst)
13 blpop(keys, timeout)
14 brpoplpush(src, dst, timeout=0)
15 自定义增量迭代
'''
import redis
conn = redis.Redis(decode_responses=True)
# 1 lpush(name,values) 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# conn.lpush('girls', '刘亦菲')
# conn.lpush('girls', '小红') # 左侧插入
# conn.rpush('girls', '小桃') # 右侧插入
# 2 lpushx(name,value) # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# conn.lpushx('girls', '小薇') # 左侧插入
# 3 rpushx(name, value) # 表示从右向左操作
# conn.rpushx('girls', '小爱') # 右侧插入
# 4 llen(name) # name对应的list元素的个数
# print(conn.llen('girls')) # 9
# 5 linsert(name, where, refvalue, value)) # 在name对应的列表的某一个值前或后插入一个新值
# conn.linsert('girls', where='after', refvalue='小爱', value='李清照')
# conn.linsert('girls', where='before', refvalue='小爱', value='小莲')
# 6 lset(name, index, value) # 对name对应的list中的某一个索引位置重新赋值
# conn.lset('girls',2,'zzz')
# 7 lrem(name, value, num) # 在name对应的list中删除指定的值
# count放数字,可以写负数,表示从右往前删除 0 表示全删
# conn.lrem('girls',0,'李清照')
# 8 lpop(name) # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# res=conn.lpop('girls')
# res1=conn.rpop('girls')
# print(res) # 小薇
# print(res1) # 小爱
# 9 lindex(name, index) # 在name对应的列表中根据索引获取列表元素
# res=conn.lindex('girls',2)
# print(res) # 小红
# 10 lrange(name, start, end) # 在name对应的列表分片获取数据 前闭后闭
# res=conn.lrange('girls',0,2)
# print(res) # ['小红', 'zzz', '小红']
# 11 ltrim(name, start, end) # 在name对应的列表中移除没有在start-end索引之间的值
# print(conn.ltrim('girls',1,2)) # Ture
# 12 rpoplpush(src, dst) # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# conn.rpoplpush('girls', 'boys')
# 13 blpop(keys, timeout) # 将多个列表排列,按照从左到右去pop对应列表的元素
# 阻塞式弹出,如果列表中没有值,会阻塞在这,直到有值,再弹出,它可以做消息队列,做分布式的系统
# res=conn.blpop('boys',timeout=3)
# print(res)
# 14 brpoplpush(src, dst, timeout=0) # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
# 15 自定义增量迭代 # 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
# # 1、获取name对应的所有列表
# # 2、循环列表
# # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能
# res=conn.lrange('girls',0,conn.llen('girls'))
# print(res)
# conn.close()
5. redis其他操作
import redis
conn = redis.Redis()
# 1 delete(*names) 删除
# conn.delete('age','name')
# 2 exists(name) 统计
# res = conn.exists('aa')
# print(res) # 1
# 3 keys(pattern='*')
# res = conn.keys('*o*')
# res1 = conn.keys('?o*')
# print(res) # [b'money', b'aaoaa', b'hobby', b'boys']
# print(res1) # [b'money', b'hobby', b'boys']
# 4 expire(name ,time)
# conn.expire('test_hash',3)
# 5 rename(src, dst) # 对redis的name重命名为
# conn.rename('aa','aaa')
# 6 move(name, db) # 将redis的某个值移动到指定的db下
# 默认操作都是0 库,总共默认有16个库
# conn.move('aaa',1)
# 7 randomkey() 随机获取一个redis的name(不删除)
# res=conn.randomkey()
# print(res)
# 8 type(name) 查看类型
res = conn.type('bb') # list hash set
print(res)
6. redis管道
redis:redis数据库,是否支持事务?
支持
不支持
1. redis事务机制可以保证一致性和隔离性,无法保证持久性,但是对于redis而言,本身是内存数据库,所以持久化不是必须属性。原子性需要自己进行检查,尽可能保证
2. redis 不像mysql一样,支持强事务,事务的四大特性不能全部满足,但是能满足一部分,通过redis的管道实现的
3. redis本身不支持事务,但是可以通过管道,实现部分事务
4. redis 通过管道,来保证命令要么都成功,要么都失败,完成事务的一致性,但是管道只能用在单实例,集群环境中,不支持pipline
import redis
conn = redis.Redis()
pipline = conn.pipeline(transaction=True) # transaction=True是否开启事务
pipline.decr('a', 2) # a减2
raise Exception('我崩了')
pipline.incr('b', 2) # b加2
pipline.execute()
conn.close()
7. django中集成redis
7.1 直接使用
from user.POOL import pool
import redis
def index(request):
conn = redis.Redis(connection_pool=pool)
conn.incr('page_view')
res = conn.get('page_view')
return HttpResponse('被你看了%次' % res)
7.2 使用第三方米模块
配置文件配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}
# "PASSWORD": "123",
}
}
}
from django_redis import get_redis_connection
def index(request):
conn = get_redis_connection(alias="default") # 每次从池中取一个链接
conn.incr('page_view')
res = conn.get('page_view')
return HttpResponse('被你看了%s次' % res)
7.3 借助于django的缓存使用redis
如果配置文件中配置了 CACHES,以后django的缓存,数据直接放在redis中
以后直接使用cache.set 设置值,可以传过期时间
使用cache.get 获取值
强大之处在于,可以直接缓存任意的python对象,底层使用pickle实现的
8. celery介绍
1. celery:翻译过来叫芹菜,它是一个 分布式的异步任务 框架
2. celery有什么用
1. 完成异步任务:可以提高项目的并发量,之前开启线程做,现在使用celery做
2. 完成延迟任务
3. 完成定时任务
3. 架构
消息中间件:broker 提交的任务(函数)都放在这里,celery本身不提供消息中间件,需要借助于第三方:redis,rabbitmq
任务执行单元:worker,真正执行任务的地方,一个个进程,执行函数
结果存储:backend,函数return的结果存储在这里,celery本身不提供结果存储,借助于第三方:redis,数据库,rabbitmq


浙公网安备 33010602011771号