一、Redis介绍
1、redis介绍
开源:早起版本2w3千行
基于键值对的存储系统:字典形式
多种数据结构:字符串,hash,列表,集合,有序集合
高性能,功能丰富
使用的公司有:github,twitter,stackoverflow,阿里,百度,微博,美团,搜狐
2、8个特性:
(1)速度快:10w ops(每秒10w读写),数据存在内存中,c语言实现,单线程模型
(2)持久化:rdb和aof
(3)多种数据结构:
5大数据结构
BitMaps位图:布隆过滤器 本质是 字符串
HyperLogLog:超小内存唯一值计数,12kb HyperLogLog 本质是 字符串
GEO:地理信息定位 本质是有序集合
(4)支持多种编程语言:基于tcp通信协议,各大编程语言都支持
(5)功能丰富:发布订阅(消息) Lua脚本,事务(pipeline)
(6)简单:源代码几万行,不依赖外部库
(7)主从复制:主服务器和从服务器,主服务器可以同步到从服务器中
(8)高可用和分布式:
2.8版本以后使用redis-sentinel支持高可用
3.0版本以后支持分布式
3、典型使用场景
缓存系统:使用最广泛的就是缓存
计数器:网站访问量,转发量,评论数(文章转发,商品销量,单线程模型,不会出现并发问题)
消息队列:发布订阅,阻塞队列实现(简单的分布式,blpop:阻塞队列,生产者消费者)
排行榜:有序集合(阅读排行,点赞排行,推荐(销量高的,推荐))
社交网络:很多特效跟社交网络匹配,粉丝数,关注数
实时系统:垃圾邮件处理系统,布隆过滤器
二、Redis安装 及配置
1、官网下载,如果没有更改安装路径,就直接下一步就可以了
2、redis相关配置
在安装目录下,找到redis.windows-service.conf,在该文件中进行配置
""" 1)绑定的ip地址,多个ip用空格隔开 bind 127.0.0.1 2)端口,默认6379,一般不做修改 port 6379 3)是否以守护进程启动,默认为no,一般改为yes代表后台启动(windows系统不支持) daemonize no 4)定义日志级别,默认值为notice,有如下4种取值: debug(记录大量日志信息,适用于开发、测试阶段) verbose(较多日志信息) notice(适量日志信息,使用于生产环境) warning(仅有部分重要、关键信息才会被记录) loglevel notice 5)配置日志文件保持地址,默认打印在命令行终端的窗口上 如果填写 "./redis.log" 就会在启动redis服务的终端所在目录下,用redis.log记录redis日志 logfile "" eg)终端首先切断到log文件夹所在目录(一般就可以采用redis的安装目录,也可以自定义),再启动reids服务 logfile "./log/redis.log" 6)数据库个数,默认是16个,没特殊情况,不建议修改 databases 16 7)数据持久化 save 900 1 # 超过900秒有1个键值对操作,会自动调用save完成数据持久化 save 300 10 # 超过300秒有10个键值对操作,会自动调用save完成数据持久化 save 60 10000 # 超过60秒有10000个键值对操作,会自动调用save完成数据持久化 8)数据库持久化到硬盘失败,redis会立即停止接收用户数据,让用户知道redis持久化异常,避免数据灾难发生(重启redis即可),默认为yes,不能做修改 stop-writes-on-bgsave-error yes 9)消耗cpu来压缩数据进行持久化,数据量小,但会消耗cpu性能,根据实际情况可以做调整 rdbcompression yes 10)增持cpu 10%性能销毁来完成持久化数据的校验,可以取消掉 rdbchecksum yes 11)持久化存储的文件名称 dbfilename dump.rdb 12)持久化存储文件的路径,默认是启动服务的终端所在目录 dir ./ 13)reids数据库密码 requirepass 密码 """
三、Redis的基本操作
1、启动服务:
""" windows系统 1)前台启动 i)打开终端切换到redis安装目录 >: cd C:AppsRedis ii)启动服务 >: redis-server redis.windows.conf 2)后台启动 i)打开终端切换到redis安装目录 >: cd C:AppsRedis ii)启动服务(后面的配置文件可以省略) >: redis-server --service-start redis.windows-service.conf """
# linux启动
redis-server
2、连接redis:
""" 1)默认连接:-h默认127.0.0.1,-p默认6379,-n默认0,-a默认无 >: redis-cli 2)完整连接: >: redis-cli -h ip地址 -p 端口号 -n 数据库编号 -a 密码 3)先连接,后输入密码 >: redis-cli -h ip地址 -p 端口号 -n 数据库编号 >: auth 密码 """
3、密码设置、修改、查找
""" 1)提倡在配置文件中配置,采用配置文件启动 requirepass 密码 2)当服务启动后,并且连入数据库(redis数据库不能轻易重启),可以再改当前服务的密码(服务重启,密码重置) config set requirepass 新密码 3)已连入数据库,可以查看当前数据库服务密码 config get requirepass """
4、其他操作:
1、切换数据库: >: select 数据库编号 2、关闭服务(前提是数据库已连接) >: shutdown # 直接连接数据库并关闭redis服务 >: redis-cli -h ip地址 -p 端口号 -n 数据库编号 -a 密码 shutdown 3、清空redis数据库(前提数据库已连接) >: flushall 4、数据持久化: 1)配置文件默认配置 >: save 900 1 # 超过900秒有1个键值对操作,会自动调用save完成数据持久化 >: save 300 10 # 超过300秒有10个键值对操作,会自动调用save完成数据持久化 >: save 60 10000 # 超过60秒有10000个键值对操作,会自动调用save完成数据持久化 2)安全机制 # 当redis服务不可控宕机,会默认调用一下save完成数据持久化(如果数据量过大,也可能存在部分数据丢失) 3)主动持久化 >: save # 连入数据库时,主动调用save完成数据持久化 注:数据持久化默认保存文件 dump.rdb,保存路径默认为启动redis服务的当前路径
四、Redis在python中的使用
1、导入依赖库 >: pip3 install redis 2、使用; import redis #decode_response=True 得到的结果会自动解码(不是二进制数据) conn=redis.Redis(host='127.0.0.1',port=6379,db=1,password=密码,decode_responses=True) #连接池: pool=redis.ConnectionPool(host='127.0.0.1',port=6379,db=1,max_connections=100,password=密码,decode_responses=True) conn_pool=redis.Redis(conncetion_pool=pool)
五、Redis数据类型
String类型操作
String类型在内存中的存储是按照一个name对应一个value来存储的
''' ex:过期时间 (单位:秒) px: 过期时间 (单位:毫秒) nx:如果设置为True,则只有name不存在时,set操作才执行,如果name存在,则修改不了,执行没有效果 xx: 如果设置为True,则只有name存在是,set操作才执行,name值存在才能修改,不存在,不会设置新值 ''' conn.set('height','180',ex=1) conn.set('height',180,px=1) conn.set('height','100',nx=True) # height结果:height=180 conn.set('height','100',xx=True) # height结果:height=100 conn.set('height1','102',xx=True) # height1结果:None ''' setnx:只用当key不存在的时候,才会执行,存在,则不会执行 等价于set('height','100',nx=True) setex(name,time,value) 等价于 set('height','180',ex=1) psetex(name,time_ms,value) 等价于 conn.set('height',180,px=1) ''' conn.set('height', '180') conn.setnx('height', '100') # 此时height 还是 180 conn.setex('height1',1,'120') # 等价于set('height',180,px=1) conn.psetex('height', 1, '110') # print(conn.get('height')) print(conn.get('height1')) ''' mset:以字典的形式插入多个 mget: 返回列表的形式 getset: 设置一个值,并返回一个原来的旧值 ''' # conn.mset({'k1': 'hello', 'k2': 'world'}) conn.mget(['k1', 'k2']) # 结果:[b'hello',b'world'] re = conn.getset('k1', '111') # 结果:返回的是k1旧值 :hello ''' getrange(key,start,end);截取value的长度,类似切片,截取超过本身长度则只取本身 setrange(key,offset,value): 在value的offset起始位置插入value值 getbit('key,offset):截取value的二进制中指定位置的值(0或者1)
setbit(key,offset,value): 将key对应的值的二进制表示的位进行操作,注意value值只能是1或者0 incr('key',amount=1): 只要执行该语句,value数字就会加amount的值,一般用于访问量统计
incrbyfloat(key,amount=1.0): 同incr一样,自增数是浮点型 decr('key',amount=1): 只要执行该语句,value数字就会减1 append('key',insert_value):原来value+insert_value。
bitop(operation,dest,*keys):
operations: AND(并)、OR(或)、NOT(非)、XOR(异或)
dest:新的Redis的key
*key: 要查找的Redis的name
bitcount(key,start=None,end=None): 获取key对应值的二进制中的某位的值
strlen(key): 返回key对应值的字节长度(一个汉字3个字节) ''' ret=conn.getrange('k1',0,3) # 原来k1 = 11111,执行后得到结果是 111, conn.setrange('k4',2,1) # 原来k4=8888 现在变成 k4=88188 print(conn.get('k4')) ret=conn.getbit('k4',3) #结果:ret=1 conn.set('k5',1) conn.incr('k5',2) conn.incr('k5') print(conn.get('k5')) # 结果:k5=4 conn.decr('k5') print(conn.get('k5')) # 结果:k5=2 conn.append('k5','oo') # 结果 k5=200
conn.bitop('AND','k6','k1','k2','k3')
Hash操作(value是字符类型)
Hash操作,redis中Hash在内存中的存储格式如下:
''' 在对应的hash中设置一个键值对(不存在,则创建,否则,修改) hset(name,key,value): name:redis的name key:字典关键字 value:字典关键字对应的值 hget(name,key): 获取name对应的hash中key对应的值 ''' conn.hset('hash1','h1',11) conn.hset('hash1','h2',22) conn.hset('hash1','h1',333) ret=conn.hget('hash1','h1') # >: 333 ''' 在对应的hash中批量设置键值对 hmset(name,mapping): name: redis的name mapping: 字典 hmget(name,keys,*args): keys:要获取key集合 *args: 要获取的key ''' conn.hmset('hash2',{'k1':1,'k2':2,'k3':3}) ret=conn.hmget('hash2','k1','k2','k3') #两者等价 ret=conn.hmget('hash2',['k1','k2','k3']) # >:结果都是 ['1','2','3'] ''' hgetall(name): 获取name对应hash的所有键值,以字典的形式返回 ''' ret=conn.hgetall('hash2') # >: {'k1': '1', 'k2': '2', 'k3': '3'} ''' hlen(name): 获取name对应的hash中键值对的个数 hkeys(name): 获取name对应的hash中所有key的值,以列表形式返回 hvals(name): 获取name对应hash中所有value的值,以列表形式返回 hexists(name,key): 判断当前hash中是否存在key hdel(name,*keys): 删除hash中指定的key的键值对 ''' ret=conn.hlen('hash2') # >: 3 ret=conn.hkeys('hash2') # >: ['k1', 'k2', 'k3'] ret=conn.hvals('hash2') # >: ['1', '2', '3'] ret=conn.hexists('hash2','k1') # >: True conn.hdel('hash2','k1','k2') # >: 2 ''' 自增name对应的hash中指定key的值,不存在则创建key=amount hincrby(name,key,amount=1): amount: 是自增数(整数) hincrbyfloat(name,key,amount=1.0) 同hincrby一样,只不过是自增数是浮点类型 ''' conn.hincrby('hash2','k1',amount=1) conn.hincrby('hash2','k1',amount=1) conn.hincrbyfloat('hash2','k2',amount=1.1) conn.hincrbyfloat('hash2','k2',amount=1.1) # >: hahs2所有键值对:{'k3': '3', 'k1': '2', 'k2': '2.2'} ''' hscan(name,cursor=0,match=None,count=None): cursor: 游标(基于游标分批获取数据) match: 匹配指定key,默认None 表示所有的key count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数 ''' #eg: # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) # ... # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 cursor1,data1=conn.hscan('hash2',cursor=0,match=None,count=None) # >:0 ,{'k3': '3', 'k1': '2', 'k2': '2.2'} ''' # 利用yield封装hscan创建生成器,实现分批去redis中获取数据 hscan_iter(name,match=None,count=None): # 参数: # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 ''' for item in conn.hscan_iter('hash2'): print(item) # >: ('k3', '3') # >: ('k1', '2') # >: ('k2', '2.2')
List列表操作
在内存中存储方式
''' lpush(name,values): 在对应的list中添加元素,每个新元素都是添加在列表的最左边 rpush(name,values)则是添加在列表的右边 ''' conn.lpush('l1',11,22,33) # >: 33,22,11 ''' lpushx(name,value): 跟lpush一样,也是添加元素, 但是,只有当name存在是才会添加,当name不存在时,则不会添加 注意: rpushx则是添加在列表右边 ''' conn.lpushx('l2',1) conn.lpushx('l1',1) ''' llen(name): 获取name对应的list元素的个数 ''' conn.llen('l1') # >: 19 ''' linsert(name,where,refvalue,value): 参数: name,redis的name where,BEFORE或AFTER(小写也可以) refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准) value,要插入的数据 ''' conn.linsert('l1',where='before',refvalue=1,value=22222) ''' lset(name,index,value): 在list的某个位置插入一个值 index: list的索引位置 value: 要设置的值 lrem(name,count,value): 删除name对应list中指定的值 value: 要删除的值 count: count=0,删除列表中所有的指定值; count=2,从前到后,删除2个; count=-2,从后向前,删除2个 lpop(name): 删除name对应list的左侧第一个元素,并返回该元素 rpop:则是右侧第一个元素 ''' conn.lset('l1',2,'1111111111') conn.lrem('l1',value=11,count=0) l=conn.lpop('l1') # >: 22222 ''' lindex(name,index): 返回索引对应的元素 lrange(name,start,end): 跟列表切片一致 ltrim(name,start,end): 在name对应的列表中移除没有在start-end索引之间的值 ''' l= conn.lindex('l1',2) # >: 22 l=conn.lrange('l1',1,10) # >: ['1111111111', '22', '33', '22', '33', '22', '33', '22', '33', '22'] conn.ltrim('l1',1,9) ''' 从一个列表取出最右边的元素,同时,将取出来的元素添加至另一个列表的最左边 rpoplpush(src,dst): src: 要取数据的列表name dst: 要添加数据的列表name 同rpoplpush一样,只不过,如果src这个列表没有数据的话,会进入阻塞状态。 brpoplpush(src,dst,timeout=0): timeout: 超时时间,0表示永远阻塞 ''' conn.rpoplpush('l1','l2') ''' 获取并移除列表第一个元素,如果列表没有元素,则会计入阻塞,直到发现可弹出元素或者等待超时为止 blpop(keys,timeout): keys: redis的name的元素集合 timeout: 超时时间,默认是0,表示永远阻塞 ''' conn.blpop(('l2','l1'),timeout=2) # >: ('l1','33') #自定义增量迭代 # 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要: # 1、获取name对应的所有列表 # 2、循环列表 # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能: import redis conn=redis.Redis(host='127.0.0.1',port=6379) # 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]) # conn.flushall() 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 print(conn.lrange('test',0,100)) for item in scan_list('test',5): print('---') print(item)
其他操作:
blpop key timeout #lpop的阻塞版,timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1) brpop key timeout #rpop的阻塞版,timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1) #要实现栈的功能 lpush+lpop #实现队列功能 lpush+rpop #固定大小的列表 lpush+ltrim #消息队列 lpush+brpop
Set操作:(不允许重复的列表)
# sadd(name,values) 添加元素,可以添加一个或多个 conn.sadd('s1', 111, 222) # scard(name) 获取name对应的集合中元素个数 conn.scard('s1') # >:2 conn.sadd('s2', 111, 333,444,555,666,777) ''' smembers(name) 获取集合中所有元素 sismember(name,value) 检测value是否是name集合的元素 ''' conn.smembers('s1') # >:{'111', '222'} conn.sismember('s1', '111') # >: True ''' sdiff(keys,*args) 差集 sdiffstore(dest,keys,*args),将差集存在一个新的集合中 参数 dest: 是新集合的name ''' conn.sdiff('s1', 's2') # 在集合s1中但是不在集合s2中的元素 # >: {'222'} conn.sdiffstore('s3','s1','s2') # >: s3={'222'} ''' sinter(keys,*args) 交集 sinterstore(dest,keys,*args) 将交集结果存在dest中 ''' conn.sinter('s1', 's2') conn.sinterstore('s3', 's1', 's2') # >: {'111'} ''' 并集: sunion(keys,*args) sunionstore(dest,keys,*args) 并集结果存于dest这个新集合中 ''' conn.sunion('s1','s2') conn.sunionstore('s3','s1','s2') ''' smove(src,dst,value):将src集合中的valuse移动到dst集合中 spop(name): 从集合的右侧移除一个成员并将其返回 ''' conn.smove('s1','s2','222') # srandmember(name,numbers):从集合随机获取 numbers个元素 conn.srandmember('s2', 2) # >:['111', '333'] # srem(name,values) 删除集合中某些值 conn.srem('s2',111,333) ''' 通哈希类型的hscan一样 sscan(name,cursor=0,match=None,count=None): cursor: 游标(基于游标分批获取数据) match: 匹配指定key,默认None 表示所有的key count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数 ''' # eg: # 第一次:cursor1, data1 = r.sscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.sscan('xx', cursor=cursor1, match=None, count=None) # ... # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 conn.sscan('s2', cursor=0, match=None, count=2) # >: (2, ['555', '111']) ''' # 利用yield封装sscan创建生成器,实现分批去redis中获取数据 sscan_iter(name,match=None,count=None): # 参数: # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 ''' for item in conn.sscan_iter('s2',match=None,count=None): print(item) # >:555 # >:111 # >: 333 # ...
有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。(结构:(name, value,score))
''' 有序集合添加元素 zadd(self, name, mapping, nx=False, xx=False, ch=False, incr=False): 参数: mapping: 字典 nx:如果设置为True,则只有name不存在时,set操作才执行,如果name存在,则修改不了,执行没有效果 xx: 如果设置为True,则只有name存在是,set操作才执行,name值存在才能修改,不存在,不会设置新值 ch: 如果为True,返回值返回的是修改的元素数。修改的元素包括添加的新元素和分数更改的元素。false则默认返回0 incr:设置为True时,当集合元素不存在时,则没有影响,若集合元素(比如:n1)存在,则会把原来的元素对应的value值,加新的value值。 ''' conn.zadd('zs1',{'n1':1,'n2':2,'n3':3,'n4':5,'n5':4}) conn.zadd('zs1',{'n1':6},incr=True) # >: n1=7 ''' name有序集合元素的数量 zcard(name) ''' conn.zcard('zs1') # >: 5 ''' 获取name对应的有序集合分数(value) 在[min,max]之间的个数 zcount(name,min,max): ''' conn.zcount('zs1',2,5) # >: 4 ''' 有序集合结构:(name,value,score) zincrby(name, amount, value): ''' conn.zincrby('zs1',amount=4,value='n1') # >: n1 对应的score 从2 变成6 ''' conn.zrange(name, start, end, desc=False, withscores=False,score_cast_func=float) 参数: name,redis的name start,有序集合索引起始位置(非分数) end,有序集合索引结束位置(非分数) desc,排序规则,默认按照分数从小到大排序 withscores,是否获取元素的分数,默认只获取元素的值 score_cast_func,对分数进行数据转换的函数 # 更多: # 从大到小排序 # zrevrange(name, start, end, withscores=False, score_cast_func=float) # 按照分数范围获取name对应的有序集合的元素 # zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float) # 从大到小排序 # zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float) ''' conn.zrange('zs1',1,5) # >: ['n3', 'n5', 'n4', 'n1'] conn.zrange('zs1',1,5,withscores=True) # >: [('n3', 3.0), ('n5', 4.0), ('n4', 5.0), ('n1', 6.0)] ''' 获取name有序集合中的value的排行位置(本质就是位置,是从0开始计) zrank(name,value) 更多: # zrevrank(name, value),从大到小排序 ''' conn.zrank('zs1','n1') # >: 4 conn.zrevrank('zs1','n1') # >: 0 ''' conn.zrangebylex(name, min, max, start=None, num=None) 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大 # 参数: # name,redis的name # min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间 # min,右区间(值) # start,对结果进行分片处理,索引位置 # num,对结果进行分片处理,索引后面的num个元素 # 如: # ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga # r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca'] # 更多: # 从大到小排序 # zrevrangebylex(name, max, min, start=None, num=None) ''' conn.zrangebylex('zs1','[n1','+') # >: ['n2', 'n3', 'n5', 'n4', 'n1'] ''' zrem(name,values) 删除name集合中values的值 zremrangebyrank(name,min,max): 根据value范围删除 zremrangebyscore(name,min,max): 根据分数范围删除 zremrangebylex(name, min, max):根据值返回删除 ''' conn.zrem('zs1',['n5','n4']) conn.zremrangebyrank('zs1',2,3) conn.zremrangebyscore('zs1',7,9) ''' 获取两个有序集合的交集,存在一个新的集合,如遇到相同值不同分数,则按照aggregate进行操作 zinterstore(dest,keys,aggregate=None) 获取两个有序集合的并集,存在一个新的集合,如遇到相同值不同分数,则按照aggregate进行操作 zunionstore(dest, keys, aggregate=None) aggregate的值为: SUM MIN MAX ''' # zs1={n1:1,n2:2,..} zs2={n1:4,b1:1,..} conn.zinterstore('zs3',('zs1','zs2'),aggregate='MAX') # >: zs3={n1:4} ''' 跟字符串的相似 zscan(name, cursor=0, match=None, count=None, score_cast_func=float) zscan_iter(name, match=None, count=None,score_cast_func=float) score_casst_func:是用来处理分数的 '''
其他操作
#delete(*names) #删除redis中的任意数据类型 conn.delete('k4','k5') exists(name) #判断name是否存在 ''' keys(pattern='*') 获取redis的name # 更多: pattern = * 匹配数据库中所有 key 。 pattern = h?llo 匹配 hello , hallo 和 hxllo 等。 pattern = h*llo 匹配 hllo 和 heeeeello 等。 pattern = h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo ''' conn.keys(pattern='*') # ['s1', 'zs1', 'zs2', 's3', 's2', 'hash1', 'k1', 'k3', 'hash2', 'name', 'k2', 'zs3', 'l1'] expire(name ,time) # 为某个redis的某个name设置超时时间 rename(src, dst) # 对redis的name(src)重命名为dst move(name, db) # 将redis的某个值移动到指定的db下 randomkey() # 随机获取一个redis的name(不删除) type(name) # 获取name对应值的类型 scan(cursor=0, match=None, count=None) scan_iter(match=None, count=None) # 同字符串操作,用于增量迭代获取key
redis的总结:
''' 列表:实现timeLine功能,时间轴,微博关注的人,按时间轴排列,在列表中放入关注人的微博的即可 集合:抽奖系统 :通过spop来弹出用户的id,活动取消,直接删除 点赞,点踩,喜欢等,用户如果点了赞,就把用户id放到该条记录的集合中 标签:给用户/文章等添加标签,sadd user:1:tags 标签1 标签2 标签3 给标签添加用户,关注该标签的人有哪些 共同好友:集合间的操作 sadd:可以做标签相关 spop/srandmember:可以做随机数相关 sadd/sinter:社交相关 有序集合:做排行榜 '''
六、 管道
管道来实现一次请求执行多条命令,减少多个命令造成的网络时延。
注意:管道是没有原子性的,同时,也不是命令越多越好
# -*-coding:utf-8 -*- import redis pool=redis.ConnectionPool(host='127.0.0.1',port=6379,password=12345) r=redis.Redis(connection_pool=pool) #transaction=True 开启事务,注意,该事务没有回滚 pip=r.pipeline(transaction=True) pip.multi() # pip.set('k4','111') pip.set('k5','5555') pip.execute() #执行
1次pipeline(n条命令)=1次网络时间+n次命令时间
''' pipeline期间将“独占”链接,此期间将不能进行非“管道”类型的其他操作,直到pipeline关闭;
如果你的pipeline的指令集很庞大,为了不干扰链接中的其他操作,你可以为pipeline操作新建Client链接,让pipeline和其他正常操作分离在2个client中。
不过pipeline事实上所能容忍的操作个数,和socket-output缓冲区大小/返回结果的数据尺寸都有很大的关系;
同时也意味着每个redis-server同时所能支撑的pipeline链接的个数,也是有限的,这将受限于server的物理内存或网络接口的缓冲能力 '''
七、事务
事务是一个单独的隔离操作,将事务中的命令进行序列化、按顺序去执行。本质:就是命令入队,按顺序执行。
注意:redis单条命令式是保存原子性,但是redis事务是不保证原子性
multi:开启事务
exec:执行事务
discard:清空事务队列,并放弃执行事务
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> exec #执行事务 1) OK 2) OK
127.0.0.1:6379> multi #开启事务 OK 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> discard # 取消事务 OK
八、Django中使用redis
1、方法一(直接使用):
先封装一个redis_pool.py文件
import redis POOl=redis.ConnectionPool(host='127.0.0.1',port=6379,password='12345',max_connections=1000)
再在视图函数views中写代码
import redis from luffy.utils.redis_pool import POOl def index(request): conn=redis.Redis(connection_pool=POOl) conn.hset('kkk','age',11) ...
2、方法二(使用django-redis模块)
(1)pip install django-redis
(2)setting里配置:
# redis配置 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/2", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} "PASSWORD": "123", } } }
(3)视图函数:
from django_redis import get_redis_connection conn = get_redis_connection('default') print(conn.hgetall('xxx'))