redis的基础---操作内存so easy
1, redis是做什么的?有哪些优势?
redis是帮助开发者在内存中操作数据的软件.
1 2 3 4 5 | - redis可以做持久化: AOF :可以定时把内存中的数据写在硬盘当中,即使宕机也可以重新把数据从文件中把数据读取到内存中. 缺点: 可能会造成数据丢失,数据不完整. RDB :每执行一条命令,就往硬盘上写一条数据,完全保证数据不会丢失,数据完整. 缺点: 效率低<br> - 相当于是大字典<br><br> - 单进程单线程 可以有多连接<br><br> - redis的特点:<br> a. 持久化<br> b. 单进程,单线程<br> c. 5 大数据类型<br> |
补充:
1 2 3 4 5 | 简单理解IO多路复用: 可以创建一个连接池,服务端与很多客户端创建连接,(因为在网络中连接是相对要耗费时间的,数据传输 相对较快),例如:此时服务端同时连接多名客户端,如果其中一个客户端请求数据,可以直接发过去, 如果很多客户同时请求数据: 可以选择单线程,单进程排队获取数据 也可以选择到多线程同时进行. |
1.1 使用连接池
1 2 3 4 5 6 7 8 | 连接池的好处: 1 , 资源重用 2 , 更快的资源响应速度 3 , 新的资源分配手段 例如: 设置某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。 4 , 统一的连接管理,避免数据库连接泄露 ## 本质: 维护一个已经和服务端连接成功的socket.以后再次发送数据时,可以获取一个socket,直接send数据就行; |
1.2 连接池实现的内部原理
2, redis的五大数据类型
1 2 3 4 5 6 7 | 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 )} 有序集合 }<br> # 注意事项: redis操作时,只有第一层value支持: list ,dict,.....<br># 慎重使用hgetall,优先使用 hscan_iter<br> |
2.1 redis的五大数据类型-------字典
2.1.1. redis操作数据的方法(增删改查)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 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 列表的增删改查操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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 自定义迭代器(灵感来自源码对字典做的迭代器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 通过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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 事务 + 一次发送多个命令 """ 在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连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 应用场景: 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实现单页面缓存
1 2 3 4 5 6 7 8 | 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实现对页面的某部分做缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报