luffy__redis配置和启动,, python操作deris普通连接_连接池——py普通连接redis_连接池链接,,redis字符串操作,,redis之hash等操作,,django使用redis方式,,接口缓存

昨日回顾

复制代码
# 1 登录前端
    Login.vue  # 小组件 放在Header.vue 组件中
    -用户名密码登录
    -短信登录
        -发送短信验证码
#2 后端发送短信接口,限制频率
    -以什么做限制,一分钟只能调用一次?
    ?mobile=11111111
        手机号
# 3 注册前端
    -发送短信验证码
    
    
    
# 4 redis介绍
    -关系型数据库:mysql,postgrasql,oracle
        -库---》表---》字段--》行 
        -结构性很强
        -sql 语句
    -非关系型数据库:reids,mongodb,elasticsearch,clickhouse。。。
        nosql
# 5 redis是什么?
    cs架构软件,存储数据的软件,用c写的,支持很多客户端(python,go,java,c,php),速度很快
    key-value形式存储,5大数据类型:字符串,字典,列表,集合,有序集合
    
# 6 为什么速度这么快
    - 纯内存操作
    - io多路复用网络模型
    - 单线程单进程,避免了锁操作和线程切换
    
    
# 7 redis适合干什么?
    -缓存(最多)
    -验证码放在redis中,有过期时间,只要过期,这个数据就没了
    -计数器 
    -去重
    -排行榜:有序集合
    -地址位置信息
    -消息队列
    。。。。
# 8 安装
    -win:一路下一步
        -创建了服务:启动停止 服务端
# 9 redis客户端:
    resp
    navicate
    cmd
复制代码

今日内容

0 redis配置和启动

复制代码
# 配置成服务---》启动停止服务即可

# 通过命令启动停止
    # 安装目录下,重要的可执行文件
    redis-cli  :客户端   等同于mysql 的 mysql
    redis-server :服务端等同于mysql 的 mysqld
    #重要的配置文件---》mysql 的 my.ini
        -redis.windows-service.conf
            - databases 16
            - port 6379
            - bind 127.0.0.1
            
            
   # 启动redis-->使用配置文件
    redis-server  配置文件路径
    redis-server redis.windows-service.conf
    
    
# 关闭
    -服务中点停止
    -cmd客户端链接上:执行   shutdown
    
# redis数据是存在内存中得
    -重启redis服务,关机---》数据都会丢失
    -咱们不会丢 redis.windows-service.conf 已经写了持久化方案
        -从内存把数据保存到硬盘上的过程称之为持久化
复制代码

python操作redis之普通链接和连接池

# 使用 py操作redis
    -pip install redis

py普通链接redis

复制代码
from redis import Redis

conn = Redis(host="localhost",
             port=6379,
             db=0,decode_responses=True)
res = conn.get('name')
print(res) # 返回\xe6\x9d\x8e\xe6\xb8\x85\xe7\x85\xa7
# print(res.decode(encoding='utf-8'))
# print(str(res,encoding='utf-8'))
# 默认字符串形式存储是以 utf-8 形式存储
conn.close()
复制代码

连接池链接

复制代码
# 1 什么是连接池---》如下图

# 2 django 操作mysql ,有没有连接池?  使用第三方解决
    -django原生操作mysql ,是没有连接池的
        -一个请求---》视图函数--》操作数据库--》创建一个mysql链接---》断开链接--》数据返回
    -django也需要有 mysql 连接池
    -django如何使用连接池?先去研究


# 3 redis自带连接池

###@@@@@@###pool.py@@@@@@###@@@@@@###@@@@@@###@@@@@@###@@@@@@###
import redis
POOL = redis.ConnectionPool(max_connections=3, host="localhost", port=6379, decode_responses=True)
###@@@@@@###@@@@@@### 测试.py@@@@@@###@@@@@@###@@@@@@###@@@@@@###
import redis
from threading import Thread
from pool import POOL
# 创建池--->保证pool是单例的---》全局只有一个pool对象实例
# python如何实现单例:6种
# 最简单方式:以模块导入 实现单例
# pool = redis.ConnectionPool(max_connections=3, host="localhost", port=6379, decode_responses=True)


# 每次从池中取一个链接
# conn = redis.Redis(connection_pool=pool)
# res = conn.get('name')
# print(res)
# conn.close()  # 把链接放回到连接池

# 起10个线程,获取链接

def task():
    conn = redis.Redis(connection_pool=POOL)
    res = conn.get('name')
    print(res)
    conn.close()  # 把链接放回到连接池


l = []
for i in range(3):
    t = Thread(target=task)
    t.start()
    l.append(t)

for t in l:
    t.join()

print('结束了')
复制代码

redis字符串操作

# 对每种数据类型的操作及这个数据类型有什么作用
# [字符串  字典  列表]     集合  有序集合
## 主要应用场景
    1 计数器
    2 做缓存--》轮播图数据---》json格式字符串---》放到redis中

from pool import POOL
import redis
conn = redis.Redis(connection_pool=POOL)
# 字符串操作
# 1 set(name, value, ex=None, px=None, nx=False, xx=False) 设置值
# conn.set('hobby','篮球')
# 带过期时间
# conn.set('age','19',ex=3)
# conn.set('age','19',px=3000)

# 如果key存在才设置或不存在才设置
# nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
# xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
# conn.set('age',19,nx=True)
# conn.set('age',99,nx=True)
# conn.set('age',99,xx=True)
# conn.set('yy',99,xx=True)

 

 

# 2 setnx(name, value) 存在就不改了
# conn.setnx('age',999) # 等同于 conn.set('age',19,nx=True)

# 3 psetex(name, time_ms, value) # 设置过期时间
# conn.psetex('xxx',3000,'阿斯顿发')
# conn.setex('xxx',3,'阿斯顿发')


# 4 mset(*args, **kwargs) 批量设置
# conn.mset({'name':'yyy','age':888,'height':180})

# 5 get(name) # 获取
# res=conn.get('name')
# print(res)

# 6 mget(keys, *args)
# res=conn.mget('name','age','height')

#'name','age','height'----> name [age,height]--->[name,age,height]
# ['name','age','height']-->['name','age','height']--->[name,age,height]
# res=conn.mget(['name','age','height'])
# print(res)


# 7 getset(name, value)
# res=conn.getset('name','彭于晏')
# # 先get,再set和 getset区别?
# print(res)

# 8 getrange(key, start, end) 数字指的是字节长度
# 字符: a b 你 中 国
# 字节: 8个bit位一个字节,存 一个字母字符 用一个字节就够了 但存中文--》utf-8---》需要3个字节存一个字符
# res=conn.getrange('name',0,2) # 前闭后闭区间
# print(res)
# print(str(res,encoding='utf-8'))

# s='lqz厉害'
# print(len(s))
# print(len(bytes(s,encoding='utf-8')))
# print(len(bytes(s,encoding='gbk')))

 

# 9 setrange(name, offset, value) # 设置字节
# conn.setrange('name',3,'eeee')

#### 比特位操作####
# 10 setbit(name, offset, value)
# print(conn.getbit('name',3))
# 11 getbit(name, offset)
# 12 bitcount(key, start=None, end=None)
# 13 bitop(operation, dest, *keys)
#### 比特位操作####


# 14 strlen(name)
# print(conn.strlen('name')) # 字节长度
# 15 incr(self, name, amount=1)
# #incrby
# conn.incrby('age') # 文章阅读量 计数器 单线程 不会有并发安全问题


# 16 incrbyfloat(self, name, amount=1.0)

# 17 decr(self, name, amount=1)
# conn.decrby('age',2)

# 18 append(key, value)

# conn.append('age',8888)
conn.append('hobby','很好')
conn.close()


'''
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)
5 get(name)
6 mget(keys, *args)
7 getset(name, value)
8 getrange(key, start, end)
9 setrange(name, offset, value)
10 setbit(name, offset, value)
11 getbit(name, offset)
12 bitcount(key, start=None, end=None)
13 bitop(operation, dest, *keys)
14 strlen(name)
15 incr(self, name, amount=1)
#incrby
16 incrbyfloat(self, name, amount=1.0)
17 decr(self, name, amount=1)
18 append(key, value)
'''

'''
你需要掌握的
get
set
setex
getrange
setrange
strlen
append

redis之hash操作

复制代码
 应用场景
    1 缓存
    2 计数器

'''
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)

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)
'''

# hash ---> 字典 key -value形式
# name ={}
from redis import Redis

conn = Redis(decode_responses=True)
# 1 hset(name, key, value) 设置值
# conn.hset('userinfo','name','lqz')
# conn.hset('userinfo','age',18)


# 2 hmset(name, mapping) 批量设置
# conn.hmset('userinfo1',{'name':'彭于晏','age':19})
# conn.hset('userinfo2', mapping={'name': '刘亦菲', 'age': 19, 'hobby': '抽烟'})

# 3 hget(name,key)
# print(conn.hget('userinfo2','hobby'))

# 4 hmget(name, keys, *args)
# print(conn.hmget('userinfo2','hobby','name','age'))
# print(conn.hmget('userinfo2',['hobby','name','age']))

# 5 hgetall(name) 慎用
# res=conn.hgetall('userinfo2')
# print(res)

# 6 hlen(name)
# print(conn.hlen('userinfo2'))

# 7 hkeys(name)
# print(conn.hkeys('userinfo2'))

# 8 hvals(name)
# print(conn.hvals('userinfo2'))

# 9 hexists(name, key)
# print(conn.hexists('userinfo2','hobby1'))

# 10 hdel(name,*keys)
# res=conn.hdel('userinfo2','hobby')
# print(res)


# 11 hincrby(name, key, amount=1)
# conn.hincrby('userinfo2','age')

# 12 hincrbyfloat(name, key, amount=1.0)
# conn.hincrbyfloat('userinfo2', 'age', amount=1.2)


###### hgetall 慎用,一次性全取出来,会撑爆内存###
# 一点点取值 ---》hscan一般不单独用
# 13 hscan(name, cursor=0, match=None, count=None)
# 造数据
# for i in range(1000):
# conn.hset('map_demo',i,'鸡蛋_%s'%i)

# 一次性取出来
# res=conn.hgetall("map_demo")
# print(res)

# 一点点取---》取的数量不准确(上下相差一点点),下次取值取决于上次的结果---》不单独使用
# res=conn.hscan('map_demo',cursor=0,count=20)
# print(res) # (数字,{数据})
# print(len(res[1]))

# res=conn.hscan('map_demo',cursor=320,count=10)
# print(res) # (数字,{数据})

# conn.hscan('map_demo')


# 14 hscan_iter(name, match=None, count=None) # 取出所有数据等同于 hgetall,但是是一点点取(count的值),一点点用
# 内部是生成器
# res=conn.hscan_iter('map_demo',count=10) # 这个数字并不是取10条,而是 每次取10条,把所有都取尽
# print(res) # generator
# for item in res:
# print(item)

# 内部具体如何实现---》内部使用了hscan
# res=conn.hscan_iter('map_demo',count=10)
# 内部通过调用 hscan实现 每次取10条,用完再继续取10条,直到所有数据都取完


conn.close()

 

'''
hset
hget
hmget
hlen
hincr
hscan_iter
'''

复制代码

redis之list操作

复制代码
# 作用
    1 跨进程间通信  ---》消息队列
    2 实现分布式
    3 队列和栈
'''
1 lpush(name, values)
2 rpush(name, values) 表示从右向左操作
3 lpushx(name, value)
4 rpushx(name, value) 表示从右向左操作
5 llen(name)
6 linsert(name, where, refvalue, value))
7 r.lset(name, index, value)
8 r.lrem(name, value, num)
9 lpop(name)
10 rpop(name) 表示从右向左操作
11 lindex(name, index)
12 lrange(name, start, end)
13 ltrim(name, start, end)
14 rpoplpush(src, dst)
15 blpop(keys, timeout)
16 r.brpop(keys, timeout),从右向左获取数据
17 brpoplpush(src, dst, timeout=0)
'''
复制代码
复制代码
1 lpush(name, values)
2 rpush(name, values) 表示从右向左操作
3 lpushx(name, value)
4 rpushx(name, value) 表示从右向左操作
5 llen(name)
6 linsert(name, where, refvalue, value))
7 r.lset(name, index, value)
8 r.lrem(name, value, num)
9 lpop(name)
10 rpop(name) 表示从右向左操作
11 lindex(name, index)
12 lrange(name, start, end)
13 ltrim(name, start, end)
14 rpoplpush(src, dst)
15 blpop(keys, timeout)
16 r.brpop(keys, timeout),从右向左获取数据
17 brpoplpush(src, dst, timeout=0)
'''

from redis import Redis

conn = Redis(decode_responses=True)

# 1 lpush(name, values)
# resp:上面是左,下面是右
# conn.lpush('girls', '刘亦菲')  # 从左侧插入值
# conn.lpush('girls', '迪丽热巴')  # 从左侧插入值

# 2 rpush(name, values) 表示从右向左操作
# conn.rpush('girls','李清照')

# 3 lpushx(name, value)
# conn.lpushx('girls','lqz')  #girls key 要存在,如果不存在,就放不进去
# conn.lpushx('boys','lqz')  #girls 要存在,如果不存在,就放不进去
# conn.lpush('boys','lqz')


# 4 rpushx(name, value) 表示从右向左操作
# conn.rpushx('girls','小红')

# 5 llen(name)
# print(conn.llen('girls'))

# 6 linsert(name, where, refvalue, value))
# 在 刘亦菲 后面插入 上海刘亦菲
# conn.linsert('girls',where='after',refvalue='刘亦菲',value='上海刘亦菲')
# conn.linsert('girls', where='before', refvalue='刘亦菲', value='山东刘亦菲')




# 7 lset(name, index, value)
# conn.lset('girls',1,'lqz')  # 从0 开始计算
# conn.lset('girls',3,'lqz')  # 从0 开始计算



# 8 r.lrem(name, value, num)
# conn.lrem('girls',1 ,'lqz') # 从左往右删1个
# conn.lrem('girls',-1 ,'lqz') # 从右往左删1个
# conn.lrem('girls',0 ,'lqz') # 所有都删除

# 9 lpop(name)
# print(conn.lpop('girls'))

# 10 rpop(name) 表示从右向左操作
# print(str(conn.rpop('girls'),encoding='utf-8'))

# 11 lindex(name, index)
# res=conn.lindex('girls',1) # 按索引取值,从0开始
# print(str(res,encoding='utf-8'))


# 12 lrange(name, start, end)
# res=conn.lrange('girls',0,1) # 前闭后闭区间
# print(res)


# 13 ltrim(name, start, end)
# conn.ltrim('girls',1,3)  # 前闭后闭


# 14 rpoplpush(src, dst) #两个列表 ,从第一个列表的右侧弹出,放到第二个列表的左侧


# 15 blpop(keys, timeout) # 阻塞式弹出--》可以做消息队列---》分布式
res=conn.blpop('boys',timeout=5)
print(res)




# 16 r.brpop(keys, timeout),从右向左获取数据

# 17 brpoplpush(src, dst, timeout=0)


conn.close()


'''
lpush
llen
lpop
lindex
lrange
blpop
'''
复制代码

redis其他操作

复制代码
# 通用操作
# delete(*names)
# exists(name)
# keys(pattern='*')
# expire(name ,time)
# rename(src, dst)
# move(name, db))
#randomkey()
# type(name)
复制代码
复制代码
from redis import Redis

conn = Redis(decode_responses=True)
# delete(*names)
# conn.delete('name','age')

# exists(name)
# res=conn.exists('userinfo1','name','height')
# print(res)


# keys(pattern='*')


# res=conn.keys('u*')
# print(res)


# expire(name ,time)
# conn.expire('girls',3)


# rename(src, dst)
# conn.rename('hobby','bobby1')

# move(name, db))
# conn.move('bobby1',2)

# randomkey()
# print(conn.randomkey())

# type(name)
print(conn.type('height')) #string
print(conn.type('map_demo')) #hash



# list
#string
# hash
# set
# zset


conn.close()
复制代码

django中使用redis

方式一:通用方式

复制代码
####### 写个pool.py
import redis
POOL = redis.ConnectionPool(max_connections=10, decode_responses=True)
###### 在哪里用,导入用即可
from utils.pool import POOL
import redis
class RedisView(ViewSet):
    def list(self, request):
        conn = redis.Redis(connection_pool=POOL)
        conn.incrby('count')
        count = conn.get('count')
        return APIResponse(msg='您是第%s个访问的' % count)
复制代码

方式二:django-redis

复制代码
#1  安装
pip install django-redis

# 2 配置文件配置
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",
        }
    }
}

# 3 在使用的位置
from django_redis import get_redis_connection
class RedisView(ViewSet):
    def list(self, request):
        conn = get_redis_connection() # 从池中获取一个链接
        conn.incrby('count')
        count = conn.get('count')
        return APIResponse(msg='您是第%s个访问的' % count)
复制代码

方式三:django的缓存

复制代码
# django内置的,可以直接操作缓存---》缓存的位置--》内存--》只要项目一重启,数据就没了
# 后期,我们要把缓存数据,放到 redis中 ,redis可以持久化,项目停止,但redis还运行,数据就不会丢

# 只要在配置文件中,如下配置,以后只要使用 cache.set  和 cache.get 通过都是去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",
        }
    }
}

# cache.set()  设置缓存
# cache.get()  获取缓存


## 以后再django中,可以直接使用
cache.set 和cache.get  操作redis,用它错缓存 ---》非常简单

## 重点:
    -优势:redis 分数据类型, 只能设置5种数据类型
       -django的缓存来讲 ,不限制类型,可以放python的任意类型
    
    -django的缓存来讲,cache.set('redis的key','不区分类型:放python的任意类型')  # person
    -cache.get('userinfo')
    -django cache 底层是基于: 把你存储的类型---》使用pickle序列化--》bytes格式---》当redis的字符串形式存到redis中
    
    
    -以后咱们做redis的操作,可以直接使用django的缓存, 不需要考虑类型
复制代码

接口缓存

复制代码
# 首页轮播图接口----》只要有一个用户访问一次首页---》就会查询一次数据库
# 用户量很大---》同时来访问首页---》不停的查询 Banner表

# django的cache---》第一次去数据库拿---》把取出来的数据,放到缓存中,以后 只要访问轮播图接口,都从缓存中取---》这个接口的响应速度就会非常快


# 接口的响应速度

# 轮播图接口改造成 有缓存的


class BannerView(GenericViewSet, CommonListModelMixin):
    # qs对象可以切片----》 limit 2
    queryset = Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNT]
    serializer_class = BannerSerializer
    def list(self, request, *args, **kwargs):
        # 缓存中如果没有,就去数据中查---》放入缓存
        # 先查缓存,缓存中有直接返回
        banner_list = cache.get('banner_list')  # 列表类型
        if not banner_list:
            # 缓存中没有:去数据库查 ,查完序列化   ListModelMixin.list
            logger.info('走了数据库')
            res = ListModelMixin.list(self, request, *args, **kwargs)
            banner_list = res.data
            cache.set('banner_list', banner_list)
        return APIResponse(results=banner_list)
    
复制代码

其他

复制代码
#1  后期如果banner表中数据变了---》由于一直取的是缓存数据---》缓存不会变--->导致数据不一致
    -解决这个问题
    -专业的叫法:双写一致性
        mysql  redis要同步写
        
        
# 2 后期,所有查询所有或单条的接口,都可以加缓存
    -封装一个 mixin的类,不需要重写list方法,只需要配置一下,就能使用缓存
    
    -作业:写一个mixin的类,只要继承,并且配置了cache_key,这个接口自带缓存
复制代码

 

posted @   拆尼斯、帕丁顿  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示