redis
0 Redis介绍
1 非关系型数据库,纯内存操作,key-value存储,性能很高
2 缓存,计数器,验证码,geo地理位置信息,发布订阅,独立用户统计
3 5大数据类型:字符串,列表,hash,集合,有序集合
4 6.x之前是单线程,单进程,为什么这么快? qps:每秒查询率:10w,真实6w
-纯内存操作
-使用了io多路复用的模型,epoll (select,poll,epoll)
-避免了线程间切换的浪费
5 redis安装
-官方提供了 源码 c语言,编译安装
-编译型语言,如果要执行,需要在不同平台编译成不同平台的可执行文件
-在linux装,编译(gcc),编译成可执行文件,就可以运行
-win:不支持win,5.x 3.x基础,一路下一步
-监听的端口是:6379
-win上自动做成服务,启动关闭服务
-使用命令启动服务端
redis-server 配置文件
-客户端连接:命令窗口
redis-cli
-python代码连接
-图形化客户端:很多
-redis-desktop-manager:一路下一步
-连远端可以,
# 补充
6 QT:平台
-使用c/C++语言在平台上开发----》图形化界面软件(GUI)
-pyqt:在qt平台上使用python代码写图形化界面
-Tkinter
7 django 2.0.7以后,如果还使用pymysql连mysql,源码不兼容,改源码
-mysqlclient:什么都不用配,直接用,不需要改源码
1 Python操作Redis之普通连接和连接池
# https://www.cnblogs.com/liuqingzheng/articles/9833534.html
# redis模块,pip install redis
##### redis之普通连接
# import redis
#
# # 拿到一个连接,通过连接操作数据
# # conn = redis.Redis()
# conn = redis.Redis(host='localhost', port=6379)
#
# conn.set('name','lqz')
#
# conn.close()
#### redis连接池
import redis
# 创建池,池的大小是10,最多放10个连接
# 池需要做成单例,整个项目全局只有一个
# Python 的模块就是天然的单例模式
from pool import POOL
# 从池中获取连接
conn=redis.Redis(connection_pool=POOL)
conn.set('age',14)
conn.close()
2 Python操作Redis之字符串操作
'''
## 字符串操作
set(name, value, ex=None, px=None, nx=False, xx=False)
setnx(name, value)
setex(name, value, time)
psetex(name, time_ms, value)
mset(*args, **kwargs)
mget({'k1': 'v1', 'k2': 'v2'})
get(name)
mget(keys, *args)
mget('k1', 'k2')
getset(name, value)
getrange(key, start, end)
setrange(name, offset, value)
setbit(name, offset, value)
getbit(name, offset)
bitcount(key, start=None, end=None)
bitop(operation, dest, *keys)
bitop("AND", 'new_name', 'n1', 'n2', 'n3')
strlen(name)
incr(self, name, amount=1)
incrbyfloat(self, name, amount=1.0)
decr(self, name, amount=1)
'''
import redis
conn=redis.Redis()
## 1 set(name, value, ex=None, px=None, nx=False, xx=False)
# nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
# xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
# conn.set('hobby','篮球',ex=8)
# conn.set('name','lqz')
# conn.set('name','egon',nx=True)
# conn.set('name','egon')
# conn.set('name','dlrb',xx=True)
# conn.set('name1','dlrb',xx=True)
## 2 setnx(name, value)
# conn.setnx('name','ddd')
# conn.setnx('name1','ddd')
## 3 setex(name, time, value)
# conn.setex('age',18,5)
##4 psetex(name, time_ms, value) 以毫秒过期时间
# conn.psetex('xx',3000,'ss')
## 5 mset(*args, **kwargs) # 批量设置和一次次设置有什么区别
# conn.mset({'name2':'egon','name3':'lyf'})
## 6 get(name) # byte格式
# print(conn.get('name2'))
## 7 mget({'k1': 'v1', 'k2': 'v2'})
# res=conn.mget('name1','name2')
# res=conn.mget(['name1','name2'])
# 8 getset(name, value)
# res=conn.getset('name1','ppp')
# print(res)
# 9 getrange(key, start, end) # 前闭后闭区间,以unicode编码存储,取字节
# res=conn.getrange('name1',0,5)
# print(res.decode('utf-8'))
# 10 setrange(name, offset, value)
# conn.setrange('name1',10,'pppppp')
# 10111111 ---> 112--->p
# 11 setbit(name, offset, value)
# conn.setbit('name1',2,0)
# 12 getbit(name, offset)
# print(conn.getbit('name1',2))
# 12 bitcount(key, start=None, end=None)
# 13 strlen(name)
# print(conn.strlen('name1'))
# 14 incr(self, name, amount=1) ****** 页面访问量
# conn.incr('name1') # 自增1
# 15 decr(self, name, amount=1) #自减
# 16 incrbyfloat(self, name, amount=1.0)
# conn.incrbyfloat('name1',1.2)
# print(res)
conn.close()
#### 记住的
'''
get
set
mget
mset
strlen
incr
'''
3 Python操作Redis之hash操作
'''
hset(name, key, value)
hmset(name, mapping)
hget(name,key)
hmget(name, keys, *args)
hgetall(name)
hlen(name)
hkeys(name)
hvals(name)
hexists(name, key)
hdel(name,*keys)
hincrby(name, key, amount=1)
hincrbyfloat(name, key, amount=1.0)
hscan(name, cursor=0, match=None, count=None)
hscan_iter(name, match=None, count=None)
'''
import redis
conn = redis.Redis()
# 1 hset(name, key, value)
# conn.hset('hash1','name','lqz')
conn.hset('hash1', 'age', '19')
# 2 hget(name,key)
# print(conn.hget('hash1','age'))
# 3 hmset(name, mapping) # 弃用了,但是还可以用
# conn.hmset('user_1_info', {'name': 'lyf', 'age': 33,'hobby':'篮球'})
# conn.hset('user_2_info', mapping={'name': 'lyf', 'age': 33,'hobby':'篮球'})
# 4 hmget(name, keys, *args)
# res=conn.hmget('user_2_info','age','hobby')
# res = conn.hmget('user_2_info', ['age', 'hobby'])
# print(res)
from redis.client import list_or_args
# conn.hmget('user_2_info','age','hobby')
# res = list_or_args('age', ['hobby', ])
#res = conn.hmget('user_2_info', ['age', 'hobby'])
# res = list_or_args(['age', 'hobby'],[])
# print(res)
# 5 hgetall(name) 获取所有 ,慎用,生产环境中,尽量不要用
# res=conn.hgetall('user_2_info')
# print(res)
# 6 hlen(name)
# res=conn.hlen('user_2_info')
# print(res)
# 7 hkeys(name)
# res=conn.hkeys('user_2_info')
# print(res)
# 8 hvals(name)
# res=conn.hvals('user_2_info')
# print(res)
# 9 hexists(name, key)
# res=conn.hexists('user_2_info','name1')
# print(res)
# 10 hdel(name,*keys)
# res=conn.hdel('user_2_info','name')
# print(res)
# 11 hincrby(name, key, amount=1)
# conn.hincrby('user_2_info','age')
# 12 hincrbyfloat(name, key, amount=1.0)
# 13 hscan(name, cursor=0, match=None, count=None) # 不要使用hgetall
# 由于无序,这个方法咱们一般不同,给hscan_iter,从hash中取出一部分值,会以count为基准,但不完全是count
# res=conn.hscan('test_hash',count=11)
# print(len(res[1]))
# 14 hscan_iter(name, match=None, count=None)
# hash 类型本身就无需
# for i in range(1000):
# conn.hset('test_hash','%s_key'%i,'鸡蛋_%s'%i)
# res=conn.hgetall('test_hash')
# 取出所有数据,跟hgetall比,更节省内存
for key in conn.hscan_iter('test_hash',count=100): # 生成器
print(key)
conn.close()
'''
记住
hset
hget
hmset
hmget
hlen
hexists
hincrby
hscan_iter:分批获取数据
'''
4 Python操作Redis之列表操作
'''
lpush(name,values)
lpushx(name,value)
llen(name)
linsert(name, where, refvalue, value))
r.lset(name, index, value)
r.lrem(name, value, num)
lpop(name)
lindex(name, index)
lrange(name, start, end)
ltrim(name, start, end)
rpoplpush(src, dst)
blpop(keys, timeout)
brpoplpush(src, dst, timeout=0)
'''
### redis 之列表操作
import redis
conn = redis.Redis()
# 1 lpush(name,values) # 从列表的左侧插入值
# conn.lpush('names','lqz','egon')
# conn.lpush('names','lyf','dlrb')
# conn.lpush('names','pyy')
# conn.rpush('names','mrzh')
# 2 lpushx(name,value) # 只能key存在,才能放进去
# conn.lpushx('names','999')
# conn.lpushx('names1','999') #不存在的放不进去
# 3 llen(name)
# print(conn.llen('names'))
# 4 linsert(name, where, refvalue, value))
# where:before或者after,大小写都可以
# conn.linsert('names','after','egon','fengjie')
# conn.linsert('names','BEFORE','egon','rh')
# 5 r.lset(name, index, value) #位置从零开始
# conn.lset('names',5,'l_egon')
# 5 r.lrem(name, num,value )
# conn.lrem('names',0,'lqz') #把内部所有lqz都移除
# conn.lrem('names',1,'lqz') #从左往右移除一个符合
# conn.lrem('names', -1, 'lqz') # 从右往左移除一个符合
# 6 lpop(name)
# conn.lpop('names') # 从左侧弹出一个
# conn.rpop('names') # 从右侧弹出一个
# 7 lindex(name, index) # 拿某个位置的值,从0开始
# res=conn.lindex('names',1)
# print(res)
# 8 lrange(name, start, end)
# res=conn.lrange('names',1,conn.llen('names')) # 获取起始到结束位置的值,前闭后闭
# print(res)
# 9 ltrim(name, start, end) # 修剪
# res=conn.ltrim('names',2,4) # 只保留2--4之间的,其他全删除
# 10 rpoplpush(src, dst) # 两个列表
# conn.lpush('names1','xx','yy')
# conn.rpoplpush('names','names1')
# 11 blpop(keys, timeout) # 阻塞式弹出,有值可以弹,没有值就夯住,直到有值,
# 基于它可以做消息队列,如果是简单的消息队列,就可以使用redis的list类型
# res=conn.blpop('names',4) # 超时时间
# print(res)
# IPC:进程间通信
# 12 brpoplpush(src, dst, timeout=0)
# 一次性把list中值全取出来
# res = conn.lrange('names', 0, conn.llen('names'))
# 自定义增量迭代取值(哪个地方用过生成器)
# 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])
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
for item in scan_list('test',2):
print(item)
conn.close()
'''
记住
lpush
llen
lrem
lindex
lpop
lrange
'''
5 Redis其他操作
# 通用操作
'''
delete(*names)
# 根据删除redis中的任意数据类型
exists(name)
# 检测redis的name是否存在
keys(pattern='*')
expire(name ,time)
# 为某个redis的某个name设置超时时间
rename(src, dst)
# 对redis的name重命名为
move(name, db))
# 将redis的某个值移动到指定的db下
randomkey()
# 随机获取一个redis的name(不删除)
type(name)
'''
import redis
conn=redis.Redis()
# 1 delete(*names)
# # 根据删除redis中的任意数据类型
# conn.delete('test_hash')
# 2 exists(name)
# # 检测redis的name是否存在
# res=conn.exists('names')
# print(res) # 1 表示存在 0表示不在
# 3 keys(pattern='*') 获取所有的key值,可以过滤
# res=conn.keys(pattern='n*')
# res=conn.keys(pattern='nam?')
# print(res)
# 4 expire(name ,time)
# # 为某个redis的某个name设置超时时间
# conn.expire('names1',9)
#5 rename(src, dst)
# # 对redis的name重命名为
# conn.rename('test','test1')
#6 move(name, db))
# # 将redis的某个值移动到指定的db下
# conn.move('hash1',5)
# 7 randomkey()
# 随机获取一个redis的name(不删除)
# res=conn.randomkey()
# print(res)
# 8 type(name) 查看key的类型 5 大数据类型
# res=conn.type('user_1_info')
# res=conn.type('name1')
# print(res)
conn.close()
6 管道(pipline)
# redis是非关系型数据库,不支持事务
# 管道,我们可以通过管道来模拟事务----》要么都成功,要么都失败:一个事务
import redis
conn = redis.Redis()
# 创建一个管道
pipe = conn.pipeline(transaction=True)
# 开启事务
pipe.multi()
#向管道中放入命令
#向管道中放入命令
pipe.decrby('egon_money',50)
# raise Exception('ssss')
pipe.incrby('lqz_money',50)
pipe.execute() #让管道中的命令执行
7 Django中使用redis
7.1 通用方案
pool.py
import redis
POOL = redis.ConnectionPool(max_connections=1000)
在使用的位置
from .pool import POOL
import redis
def test(request):
conn = redis.Redis(connection_pool=POOL)
res=conn.get('name')
print(res)
return HttpResponse('ok')
7.2 django方案,第三方模块
pip install django-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",
}
}
}
# 使用的位置
from django_redis import get_redis_connection
def test(request):
conn = get_redis_connection() #从连接池中拿一个连接
res=conn.get('name')
print(res)
return HttpResponse('ok')
# 一旦使用了它,后续的djagno缓存,都缓存到redis中
cache.set('name','xxx')
# django的缓存很高级,可以缓存python中所有的数据类型,包括对象---》把对象通过pickle序列化成二进制,存到redis的字符串中

浙公网安备 33010602011771号