redis的基础---操作内存so easy

1, redis是做什么的?有哪些优势?

redis是帮助开发者在内存中操作数据的软件.

- redis可以做持久化:
    AOF :可以定时把内存中的数据写在硬盘当中,即使宕机也可以重新把数据从文件中把数据读取到内存中.
    缺点: 可能会造成数据丢失,数据不完整.
    RDB :每执行一条命令,就往硬盘上写一条数据,完全保证数据不会丢失,数据完整.
    缺点: 效率低
- 相当于是大字典

- 单进程单线程 可以有多连接

- redis的特点:
    a. 持久化
    b. 单进程,单线程
    c. 5大数据类型

 补充:

简单理解IO多路复用: 
        可以创建一个连接池,服务端与很多客户端创建连接,(因为在网络中连接是相对要耗费时间的,数据传输
	相对较快),例如:此时服务端同时连接多名客户端,如果其中一个客户端请求数据,可以直接发过去,
	如果很多客户同时请求数据: 可以选择单线程,单进程排队获取数据
	也可以选择到多线程同时进行.    

 1.1 使用连接池

连接池的好处: 
    1, 资源重用
    2, 更快的资源响应速度
    3, 新的资源分配手段
            例如: 设置某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
    4, 统一的连接管理,避免数据库连接泄露
    
## 本质: 维护一个已经和服务端连接成功的socket.以后再次发送数据时,可以获取一个socket,直接send数据就行;

 1.2 连接池实现的内部原理

 

 

 

 

 

 

 

 

 

 2, redis的五大数据类型

redis={
            k1:'123',								字符串
            k2:[12,11,22,11,33,5],						列表
            k3:{1,2,3,5},							集合
            k4:{name:123,age:18},						字典
            k5:{('alex',60),('eva-j',100),('日天':70)}	              有序集合
        }
# 注意事项: redis操作时,只有第一层value支持: list ,dict,.....
# 慎重使用hgetall,优先使用 hscan_iter

 2.1  redis的五大数据类型-------字典

  2.1.1. redis操作数据的方法(增删改查)

hset(name, key,value)  # redis中的hash指的是字典
	# name对应的是hash中设置的一个键值对(不存在,则创建;否则,修改)\
    # 参数:
    	# name, redis的name
        # key, name对应字典中的key
        # value,name对应的hash中的value
    # 注: hsetnx(name,key,value),当name对应的字典中不存在当前key时则创建(相当于添加)
    
hmset(name,mapping)
	# 在name对应的字典中批量设置键值对
    # 参数:
    	# name,  redis的name
        # mapping,	字典;如{'k1':'v1','k2':'v2'}
    # 如:
    	# r.hmset('xx',{'k1':'v1','k2':'v2'})
        
 hget(name,key)
	# 在name对应的字典中根据key获取value
    
hmget(name,keys,*args)
	# 在name对应的字典中获取多个key的值
    # 参数:
    	# name,redis对应的name
        # keys,要获取key集合,如: ['k1','k2','k3']
        # *args,要获取的key,如:k1,k2,k3
    # 如:
    	# r.mget('xx',['k1','k2'])
        # 或
        # print(r.hmget('xx','k1','k2'))

hgetall(name)
	# 获取name对应的字典的所有键值
    
hlen(name)
	# 获取name对应的字典中键值对的个数
    
hkeys(name)
	# 获取name对应的字典中所有的key
    
hvals(name)
	# 获取name对应的字典中的所有valve

hexists(name,key)
	# 检查name对应的字典中是否存在当前传入的key
    
hdel(name,*key)
	# 将name对应的字典中指定key的键值对删除
    
hincrby(name,key,amount=1)
	# 自增name对应的字典中的指定key的值,不存在则创建key=amount
    # 参数:
    	# name,	redis中的name
        # key, 	字典对应的key
        # amount	自增数(整数)

hincrbyfloat(name,key,amount=1.0)
	# 自增name对应的字典中指定key的值,不存在则创建key=amount
    # 参数:
    	# name   redis中的name
        # key, 	 字典中对应的key
        # amount 自增数(浮点数)
    
hscan(name,cursor=0,match=None,count=None)
	# 增量式迭代获取,对数据量大的数据非常有用,hacan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放在内存被撑爆
    # 参数:
    	# name  redis的name
        # cursor	游标(基于游标分批获取数据)
        # match, 	匹配指定key,默认None,表示所有的key
        # count	  每次分片获取个数,默认none表示采用redis的默认分片个数
   #如:
		# 第一次: cursor1,data1=r.hscan('xx',cursor=0,match=None,count=None)
		# 第二次: cursor2,data1=r.hscan('xx',cursor=cursor1,match=None,count=None)
        # ...
        # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
        
hscan_iter(name,match=None,count=None)
	# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
    # 参数:
    	# match, 匹配指定key,默认None 表示所有的key
        # count  每次分片最少获取个数,默认None表示采用Redis的默认分片数
如:        
	## 正确示范, 用生成器,每次取100条直到取完, 且不会占用过多内存
    ret = conn.hscan_iter('k4',count=100)
    for item in ret:
        print(item)
    	 

 2.1.2 hscan_iter -----redis为字典内置的生成器

 

 2.2  redis五大数据类型------列表

2.2.1 列表的增删改查操作

lpush(name,values)   # 在list中添加元素,每个新的元素都添加到列表的左边
	例: conn.lpush('k1',11,22,33)
    保存顺序为: 33,22,11
	# 扩展 rpush(name,value)	表示从右向左操作
lpushx(name,value)	# 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
	# 扩展 rpush(name,value)  表示从右向左操作
llen(name)	# name对应的list元素的个数
linsert(name,where,refvalue,value) # 在name对应的列表的指定位置插入新值
	# 参数:
    	# name ,		redis的name
        # where, 		before或after
        # refvalue		标杆值,即:在它的前后插入数据
        # value			要插入的数据
lset(name,index,value)  # 对name对应的list中的某一个索引位置重新赋值  (更新操作)
	# 参数:
    	# name			redis的name
        # index			list的索引位置
        # value			要设置的值
lrem(name,value,num)  # 在name对应的list中删除指定的值
	# 参数:
    	# name			redis的name
        # value			要删除的值
        # num,			 num=0 删除列表中所有的指定值
        				# num=2 从前到后, 删除2个;
            			# num=-2 从后向前, 删除2个.
lpop(name)	#在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
	# 扩展
    	# rpop(name)    表示从右向左操作
lindex(name,index)  # 在name对应的列表中根据索引获取列表元素
lrange(name,start,end) 		# 在name对应的列表中分片获取数据
	# 参数:
    	# name			redis的name
        # start			索引的起始位置
        # end			索引结束的位置
ltrim(name,start,end)		# 在name对应的列表中移除没有在start-end索引之间的值
	# 参数
    	# name			redis的name
        # start			索引的起始位置
        # end			索引的结束位置
rpoplpush(src,dst)		# 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
	# 参数
    	# src  			要取数据的列表的name
        # dst			要添加数据的列表的name
blpop(keys,timeout)	# 将多个列表排列, 按照从左到右的顺序去pop对应列表的元素
	# 参数:
    	# keys		redis的name集合
        # timeout	超时时间,当所有列表的所有元素获取完之后,阻塞等待列表内有数据的时间(秒), 0表示永远阻塞
    # 更多:
    	# brpop(keys,timeout),	从右向左获取数据
brpoplpush(src,dst,timeout=0)  # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
	# 参数:
    	# src		要取元素的列表对应的name
        # sdt		要插入元素的猎豹对应的name
        # timeout	当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0表示永远阻塞

## 补充
	堆/队列(queue) : 先进先出, 就像一个管道
    栈: 后进先出,就像弹夹, 砌墙的砖头-----后来居上

 2.2.2  自定义迭代器(灵感来自源码对字典做的迭代器)

# 通过yield创建一个生成器完成一点一点获取(通过字典操作的源码来的灵感)
conn.lpush('k1',*[11,22,33,444,55,42,45,56,76,88,79,34,23])
# 给redis的列表做一个生成器,使数据能够一点一点的取出,不至于占用大量的资源,引发爆栈
def list_iter(key,count=100):
    index = 0
    while True:
        data_list=conn.lrange(key,index,index+count-1)
        if not data_list:
            break
        index +=count
        for item in data_list:
            yield item

for item in list_iter('k1',count=20):
    print(item)

 2.2.3 在redis中进行事务操作

事务 + 一次发送多个命令 
"""
在redis中进行事务操作  ---如果成功就一起成功,失败就一起失败  同生共死

transaction    n. 交易,买卖,业务
execute         执行
"""
import redis
conn=redis.Redis(host='10.0.0.210',port=6379,password=123456)
pipe = conn.pipeline(transaction=True)
pipe.multi()

pipe.set('k2','大风吹')
pipe.hset('k3','n1',666)
pipe.lpush('k4','吴琪')

pipe.execute()

 

 

3. 在pycharm中使用redis,控制内存

3.1 在Python中创建redis连接

应用场景:
    D:\GIT&前后端分离(后端)\day110
    1,自定义使用redis
    	D:\GIT&前后端分离(后端)\day110\app01
    2,使用第三方组件
   		 D:\GIT&前后端分离(后端)\day110\app02
    	配置:
            # redis配置
CACHES ={
    'default':{
        "BACKEND":"django_redis.cache.RedisCache",
        "LOCATION":"redis://10.0.0.210:6379",
        "OPTIONS":{
            "CLIENT_CLASS":"django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS":{"max_connections":1000},
            "PASSWORD":123456,
        }, 
    },#  可以配置多个redis连接
}
		使用:
        from django.shortcuts import HttpResponse
        # 借助django的redis组件,实现对内存的控制,需要在settings中设置redis的CACHES配置
        from django_redis import get_redis_connection

        def django_index(request):
            conn=get_redis_connection("default")

            return HttpResponse('设置成功')

        def django_order(request):
            conn=get_redis_connection('back')

            return HttpResponse('获取成功')

 3.2.1. 全站缓存(整个网站的所有页面都做缓存)

 

 

 

 3.2.2  redis实现单页面缓存

import time
from django.views.decorators.cache import cache_page

@cache_page(60*15)  
def django_index(request):
	# 单视图缓存 需要用到装饰器, 装饰器的优先级比全局的优先级要高  ,ps: 对此页面做15分钟的缓存
    ctime=str(time.time())
    return HttpResponse(ctime)

 3.2.3 redis实现对页面的某部分做缓存

def django_order(request):
    # 对页面的某部分做缓存

    return render(request,'order.html')


## order.html页面
{% load cache %}        ## 导入
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>advVS的地方</h1>
    <div>
        asdf
    </div>
    {% cache 5000 缓存key %}
        缓存内容    ## 这里是单页面的局部视图的缓存,占用的内存空间更少,更精准.
    {% endcache %}
</body>
</html>

 

posted @ 2022-06-28 17:10  凉城以北  阅读(49)  评论(0)    收藏  举报