14 Redis

Redis

一、redis简单使用

1、下载

radic :https://github.com/tporadowski/redis/releases
Redis可视化工具 Redis Desktop Manager: http://pan.baidu.com/s/1kU8sY3P

2、redis介绍和安装

# redis是:数据库,非关系型数据库,nosql数据库(Not Only SQL)
	-key-value形式存储,5大数据类型:字符串,列表,字典(hash),集合,有序集合
    -纯内存,存取都在内存,速度很快  10w qps,6w左右
    -redis特点:
    	-可以持久化,可以永久存储,存到硬盘上
		-单线程,单进程, 6.x之前是,6.x
    -为什么redis单线程架构还这么快?
    	-纯内存操作
        -单线程,单进程架构,不存在线程,进程间切换造成的浪费(6.x没有了)
        -高效的网络模型--》IO多路复用  (IO模型,select和epoll的区别)
		-http://liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/25-IO%E6%A8%A1%E5%9E%8B/

# redis和Memcached
	-都是内存操作,速度都很快,基本都用来做缓存
    -reids支持持久化,Memcached只支持字符串,不支持其他类型

# 安装:
	-开源软件,意大利,C写的,初期代码只有1w多行
    -使用了IO多路复用的:epoll模型,epoll不支持win,在win的支持就不好
    -微软官方给支持:https://github.com/MicrosoftArchive/redis/releases 
	-第三方:https://github.com/tporadowski/redis/releases
     -win一路下一步,做成服务
    -mac和linux都是编译安装
     -端口:6379
        
# redis 启动和停止
	-win:启动服务和停止服务即可
    -任意路径敲:redis-server   就可以启动服务
	-带配置文件启动:redis-service redis.windows-service.conf
    
 # 可执行文件
	redis-server:启动服务  类似于 mysqld
    redis-cli:客户端命令  类似于 mysql
    
    
 # redis-desktop-manager-0.9.3.817  类似于Navicate
	-原来开源免费,后来收费了
    -目前来说,只能用我这个

3、redis的使用

set name meng

4、简单使用

# pip install redis

from redis import Redis
conn = Redis()
ret = conn.get('name')  # 连接对象
print(ret)
conn.close
# 输出:b'meng'

二、Python操作Redis之链接池

1、链接池

# 链接池
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379, max_connections=100)  # 造一个连接池,最多放100个链接
res = redis.Redis(connection_pool=pool)  # 只要执行这一句话,就是从池子拿出一个链接
ret = res.get('name')
print(ret)
conn.close  # 把链接放回到链接池

# 但是不能这么用,因为链接一次造一个pool

2、scripts/t_redis_pool.py: 封装pool

# 链接池
import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379, max_connections=100)

3、scripts/t_redis.py: 引用使用

# # 链接池
import redis
from t_redis_pool import POOL
'''
以脚本方式运行使用相对路径会报错
使用包的模式可以是用相对路径,根据导入包的路径
'''

res = redis.Redis(connection_pool=POOL)  # 只要执行这一句话,就是从池子拿出一个链接
ret = res.get('name')
print(ret)

三、Redis五大类型

1、字符类型

# 用的多:常用操作
'''
## 常用操作
1 set(name, value, ex=None, px=None, nx=False, xx=False):放里面以key:value的形式存值
2 setnx(name, value):当name有值,修改不了
3 get(name):获取存入的值
4 mget(keys, *args):批量获取
5 getset(name, value):先获取,在设置值
6 getrange(key, start, end):获取范围的值
7 setrange(name, offset, value):根据索引设置值
8 setbit(name, offset, value):设置bit位
9 getbit(name, offset):获取bit位
10 bitcount(key, start=None, end=None):统计有多少个1
11 bitop(operation, dest, *keys)
12 strlen(name):统计字节的长度
13 incr(self, name, amount=1):自增,适用于访问量,,阅读量
14 incrbyfloat(self, name, amount=1.0):自增float
15 decr(self, name, amount=1):自减
16 append(key, value):追加值
'''

from redis import Redis
conn=Redis()
1、 set(name, value, ex=None, px=None, nx=False, xx=False)

conn.set('hobby','篮球',ex=3)
conn.set('hobby','pp',nx=True) # 没有,放能放进去,如果有,不会修改掉原来的
conn.set('hobby1','pp',xx=True) # 没有,放能放进去,如果有,不会修改掉原来的

'''
ex,过期时间(秒)
px,过期时间(毫秒)
# 用redis做分布式锁
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''

2、 setnx  就是set 但是nx=True
conn.setnx('hobby','oooo')

3、 get(name)   --->bytes格式
res=conn.get('hobby')


4、 mget(keys, *args)
res=conn.mget(keys=['name','age','hobby'])
res=conn.mget('name','age','hobby')

5、 getset(name, value)
res=conn.getset('name','彭于晏')

6、 getrange(key, start, end)   前闭后闭区间 ----》字节还是字符?字节
res=str(conn.getrange('name',0,3),encoding='utf-8')
res=conn.getrange('name',0,2).decode('utf-8')

7、 setrange(name, offset, value)
conn.setrange('name',1,'lqz')

8、 setbit(name, offset, value) 不需要
res=conn.getbit('name',1)
conn.setbit('name',1,0)

9、 getbit(name, offset)
10、 bitcount(key, start=None, end=None)

12、 strlen(name)   字节长度
res=conn.strlen('name')

13、 incr(self, name, amount=1)  自增,统计网站,文章,课程访问量
conn.incr('age')

14、 incrbyfloat(self, name, amount=1.0)
conn.incrbyfloat('age',8.9)

15、 decr(self, name, amount=1)
conn.decr('age')

16、 append(key, value)
conn.append('age','nb')
conn.close()

''''
get
set
strlen
append
'''

2、列表操作

'''
1 lpush(name,values):从列表最左边里添加元素值
2 lpushx(name,value):只有name存在,值才可以插入
3 llen(name):查看列表的长度
4 linsert(name, where, refvalue, value)):在某个位置插入
5 lrem(name, value, num):删除值
6 lpop(name):从左侧弹出值
7 lindex(name, index):获取第几个位置的值
8 lrange(name, start, end):获取范围的值
9 ltrim(name, start, end):修剪,只留范围的值
10 rpoplpush(src, dst):从右侧弹出值,放到左边列表
11 blpop(keys, timeout):如果列表没有值,会卡在在这里
12 brpoplpush(src, dst, timeout=0)


'''

from redis import Redis
conn=Redis()
1、 lpush(name,values)   # 从列表左侧插入值
conn.lpush('list1','小明')
conn.lpush('list1','小红')
conn.lpush('list1','小张')
conn.rpush('list1','小方')

2、 lpushx(name,value)   # name值存在才能插入,否则无变化
conn.lpushx('list2','小刚')
conn.lpushx('list1','小刚')

3、 llen(name)   # 列表长度

res=conn.llen('list1')

4、 linsert(name, where, refvalue, value))
'''
    # name,redis的name
    # where,BEFORE或AFTER(小写也可以)
    # refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
    # value,要插入的数据
'''
res=conn.linsert('list1','before','小红','lqz')  # 有重复的,左侧开始第一个


5、 lrem(name, count, value)
'''
num=0,删除列表中所有的指定值;
num=2,从前到后,删除2个;
num=-2,从后向前,删除2个
'''
res=conn.lrem('list1','-2','小红')

lset(name, index, value)  该某个位置的值,从0开始
conn.lset('list1',0,'刘德华')


6、 lpop(name)  # 从左侧弹出
res=conn.lpop('list1')
res=conn.rpop('list1')

7、 lindex(name, index)
res=conn.lindex('list1',1)

8、 lrange(name, start, end)
res=conn.lrange('list1',0,2)   # 前闭后闭

9、 ltrim(name, start, end)
res=conn.ltrim('list1',1,10)   # 只留这部分


10、 rpoplpush(src, dst)
conn.lpush('list2','lqz')
conn.rpoplpush('list1','list2')

11、 blpop(keys, timeout)  # 如果列表中没有值,会卡在这等着,直到有值,等待多长时间
res=conn.blpop('list2',50)
print(res)
12brpoplpush(src, dst, timeout=0)
conn.close()

'''
lpush
lpop
llen
lset
blpop
'''

3、哈希(字典)操作

'''
1 hset(name, key, value):存值
    # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
2 hmset(name, mapping):批量设置值
3 hget(name,key):获取值
4 hgetall(name):获取所有值
5 hkeys(name):获取所有key
6 hvals(name):获取所有value
7 hexists(name, key):判断key是否存在
8 hdel(name,*keys):删除值
9 hincrby(name, key, amount=1):
10 hincrbyfloat(name, key, amount=1.0)
11 hscan(name, cursor=0, match=None, count=None):分批获取值,因为数据比较庞大内存不支持,所以要分批获取值
12 hscan_iter(name, match=None, count=None):获取所有,分批获取,一次拿10条数据
'''

from redis import Redis

conn = Redis()
1、 hset(name, key, value)
conn.hset('wife', 'name', '刘亦菲')
conn.hset('wife', 'age', 34)
conn.hset('wife', 'height', 167)

2、 hmset(name, mapping)
conn.hmset('userinfo',{'name':'lqz','age':19})

3、 hget(name,key)
res=conn.hget('userinfo','age')

4、 hgetall(name)
res=type(conn.hgetall('userinfo'))
res=conn.hgetall('userinfo')[b'age']

5、 hkeys(name)
res=conn.hkeys('userinfo')

6、 hvals(name)
res=conn.hvals('userinfo')

7、 hexists(name, key)
res=conn.hexists('userinfo','age')

8、 hdel(name,*keys)
res=conn.hdel('userinfo','wife')
res=conn.hdel('wife','name','age','xx')

9、 hincrby(name, key, amount=1)
res=conn.hincrby('wife','height')

10、 hincrbyfloat(name, key, amount=1.0)


11、 hscan(name, cursor=0, match=None, count=None)
https://www.cnblogs.com/xieqiankun/p/python_dict.html
for i in range(1000):
    conn.hset('test1', 'test_%s' % i, '鸡蛋%s号' % i)

res=conn.hscan('test1',cursor=0,count=11)
res=conn.hscan('test1',cursor=0,count=22)
print(res)
print(len(res[1]))
res=conn.hscan('test1',cursor=32,count=11)
print(res)
print(len(res[1]))


12、 hscan_iter(name, match=None, count=None)
# 获取所有,hgetall,它是分批获取
res=conn.hscan_iter('test1',count=100)  # generator
print(res)
for i in res:
    print(i)
conn.close()
'''
hset
hget
hmset
hmget
hexists
'''

4、通用操作

'''
1 delete(*names):根据删除redis中的任意数据类型
2 exists(name):检测redis的name是否存在
3、 keys(pattern='*'):获取所有的key
4 expire(name ,time):设计过期时间
5 rename(src, dst):重命名
6 move(name, db)):移动库
7 randomkey():随件删除一个key
8 type(name):查看类型
'''

from redis import Redis
conn=Redis()
1、 delete(*names)
conn.delete('hobby') # 根据删除redis中的任意数据类型

2、 exists(name)
res=conn.exists('list1','test1')
print(res) # 检测redis的name是否存在  *表示多个字符  ? 表示一个字符
3、 keys(pattern='*')
res=conn.keys(pattern='l*')
res=conn.keys(pattern='lis?')
print(res)

4、 expire(name ,time)
conn.expire('list1',3)


5、 rename(src, dst)
conn.rename('test1','test2')

6、 move(name, db)
conn.move('test2',1)

7 randomkey()  # 随机取一个key值,不删除
res=conn.randomkey()
print(res)

8 type(name)
res=conn.type('userinfo')
print(res)

四、Django中使用redis

1、django-redis安装

pip install django-redis

2、django-redis的使用

# 1.将缓存存储位置配置到redis中:settings.py
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},
            "DECODE_RESPONSES": True,
            "PASSWORD": "",
        }
    }
}

# 2.操作cache模块直接操作缓存:views.py
from django.core.cache import cache  # 结合配置文件实现插拔式
# 存放token,可以直接设置过期时间
cache.set('token', 'header.payload.signature', 300)
# 取出token
token = cache.get('token')

五、接口缓存

1、home/views.py

# 首页轮播图加入缓存中

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import Banner
from .serializers import BannerSerializer
from django.conf import settings
from django.core.cache import cache
from rest_framework.response import Response

class BannerView(GenericViewSet, ListModelMixin):
    serializer_class = BannerSerializer
    queryset = Banner.objects.all().filter(is_delete=False, is_show=True)[:settings.BANNER_COUNT]  # 通过切片值只显示几张图片

    def list(self, request, *args, **kwargs):  # 重写list方法

        # 把data的数据加入缓存
        # 先去缓存拿数据
        banner_list = cache.get('banner_list')
        if not banner_list:
            # 缓存没有,去数据库里面拿
            response = super().list(request, *args, **kwargs)
            # 加入缓存
            cache.set('banner_list', response.data, 60*60*24)
            return response
        return Response(data=banner_list)
posted @ 2022-02-28 17:01  迷恋~以成伤  阅读(41)  评论(0编辑  收藏  举报