Redis
一、redis介绍和安装
1. redis 是什么
- 数据库就是个存数据的地方:只是不同的数据库数据组织,存放形式不一样
- mysql 关系型数据库(oracle,sqlserver,postgrasql)
- 非关系型数据(no sql ):redis,mongodb,clickhouse,infludb,elasticsearch,hadoop。。。
- 没有sql:没有sql语句
- not only sql 不仅仅是sql
- redis:一款纯内存存储的非关系型数据库(数据都在内存),速度非常快
2. redis特点
https://www.cnblogs.com/liuqingzheng/articles/9833534.html
- redis 是一个key-value存储系统
- 数据类型丰富,支持5大数据类型:字符串,列表,hash(字典),集合,有序集合
redis={ k1:'123', 字符串 k2:[1,2,3,4], 列表/数组 k3:{1,2,3,4} 集合 k4:{name:lqz,age:12} 字典/哈希表 k5:{('lqz',18),('egon',33)} 有序集合 }
- 纯内存操作
- 可以持久化:能把内存数据,保存到硬盘上永久存储
3. redis为什么这么快
-1. 纯内存,减少io
- 2. 使用了 io 多路复用的epoll网络模型
- 3. 数据操作是单线程,避免了线程间切换
- 多客户端同时操作,不会存在并发安全问题
-4. 安装
- redis:最新是7,公司里5,6 用的比较多
- redis:开源软件,免费的,但他们不支持win
- epoll模型不支持win
- 微软官方:基于源码修改 ---》编译成可执行文件
- 第三方:https://github.com/tporadowski/redis/releases/
- win:下载安装包,一路下一步
- 安装目录在环境变量中:任意路径敲:redis-server reidis-cli 都能找到
- 把 redis做成了服务,以后通过服务启动即可
- win,mac:两个可执行文件:
redis-server :等同于 mysqld
reidis-cli :等同于mysql
5. 启动,连接
5.1 启动方式
- 使用服务启动
redis-server
redis.windows-service.conf
# 以上命令的执行和服务启动的效果是一样的
- 使用命令启动:redis-server
5.2 连接
redis-cli
redis-cli -h 地址 -p 端口(默认端口:6379)
5.3 图形化客户端(Navicate)
- resp:后来收费了
- 连接上发现有16个库
连接成功:
6. 放值
使用resp放入值
7. 取值
cmd 中连接:get key
二、python操作redis
1. python 操作Redis之普通连接
from redis import Redis conn = Redis(host='localhost', port=6379, db=0, decode_responses=True) # 简单测试 # res = conn.lpush('girls','刘亦菲') # 从左边插入值 res = conn.get('name') # pyy print(res) conn.close()
结果:
2. Redis连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
import redis from threading import Thread from pool import POOL # 作为模块导入,连接的都是同一个连接池 def task(): conn = redis.Redis(connection_pool=POOL) print(conn.get('name')) #字节类型 conn.close() if __name__ == '__main__': for i in range(10): t = Thread(target=task) t.start()
结果:
三、redis字符串类型
1. redis模块封装了很多方法---》set get mset---》跟命令是一一对应的
2.以后如果遇到redis这个模块没有封装的方法,直接使用:execute_command
String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图:
1. set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
eg:
import redis conn = redis.Redis(decode_responses=True) # 1 set(name, value, ex=None, px=None, nx=False, xx=False) # conn.set('hobby', '游泳') # conn.set('age', 18, ex=5) # ex=5 s: 过期时间为5秒,5秒后Resp中的age就没了 # conn.set('age',19,px=5000) # px=5000 ms:过期时间为5秒,5秒后Resp中的age就没了 # conn.set('age', 20, nx=True) # nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果 conn.set('age', 19, nx=True) # 因为age已经存在,所以set操作无效,修改不了age的值 conn.close()
如图:
结果:
2. setnx(name,value) :当name不存在时,设置值,存在则操作无效
# 2 setnx(name, value) conn.setnx('hy', 19) # 设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
结果:
3. setex(name,time, value) # 设置过期时间(以秒为单位)
# 3 setex(name,time, value) conn.setex('hy',5,18) # 将hy 的值修改为18,5秒后过期
结果:
5秒后:
4. psetex(name, time_ms, value) :设置过期时间(以毫秒为单位),值不存在,就设置值,存在则修改值
# 4 psetex(name, time_ms, value) conn.psetex('hy',5000,'hhy')
结果:
5秒之后:
5. mset(*args,**kwagrs):批量设置
# 5 mset(*args, **kwargs) 批量设置,一次性,设置多个值 conn.mset({'name':'hhy','age':19,'gender':'男'})
结果:
6. get(name) :获取值
# 6 get(name) #获取值 print(conn.get('name'))
结果:
7. mget(keys, *args) :批量获取
# 7 mget(keys, *args) #批量获取 print(conn.mget(['name','age','gender']))
结果:
8. getset(name, value) :等同于 get set,设置新值并获取原来的值
# 8 getset(name, value) # 等同于 get set print(conn.getset('name','adc'))
结果:
9. getrange(key, start, end) :前后都是闭区间,获取子序列(根据字节获取,非字符)
# 9 getrange(key, start, end) print(conn.getrange('name',1,2)) # 前闭后闭区间
结果:
10. setrange(name, offset, value):修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 10 setrange(name, offset, value) # offset,字符串的索引,字节(一个汉字三个字节) conn.setrange('name',2,'ooo')
结果:
11. strlen(name):返回name对应值的字节长度(一个汉字3个字节,一个字母1个字节)
# 11 strlen(name) print(conn.strlen('name'))
结果:
12.incr(self, name, amount=1): 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 12 incr(self, name, amount=1) # incr 和 incrby 一样 conn.incr('age',2) # 自加2,单线程,没有并发安全,数据不会错乱,天然适合计数器 计数器---》日活(日活跃用户数,只要有用户登录,就+1)
结果:
13. incrbyfloat(self, name, amount=1.0):自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 13 incrbyfloat(self, name, amount=1.0) amount,自增数(浮点型),有浮动 conn.incrbyfloat('age',1.1)
结果:
14.decr(self, name, amount=1):自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 14 decr(self, name, amount=1) # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。 conn.decr('age')
结果:
15. append(key, value):在redis name对应的值后面追加内容
# 15 append(key, value) # 在value的右侧加 conn.append('name','ee')
结果:
操作比特位---》后面聊
setbit(name,offset,value)
# 对name对应值的二进制表示的位进行操作 # 参数: # name,redis的name # offset,位的索引(将值变换成二进制后再进行索引) # value,值只能是 1 或 0 # 注:如果在Redis中有一个对应: n1 = "foo", 那么字符串foo的二进制表示为:01100110 01101111 01101111 所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1, 那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
getbit(name, offset)
# 获取name对应的值的二进制表示中的某位的值 (0或1)
bitcount(key, start=None, end=None)
# 获取name对应的值的二进制表示中 1 的个数 # 参数: # key,Redis的name # start,位起始位置 # end,位结束位置
bitop(operation, dest, *keys)
# 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值 # 参数: # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或) # dest, 新的Redis的name # *keys,要查找的Redis的name # 如: bitop("AND", 'new_name', 'n1', 'n2', 'n3') # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
四、Redis操作之List操作
List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:
1. lpush(name,values):在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# 1 lpush(name, values) # 从左边插入值 conn.lpush('girls','迪丽热巴')
结果:
2. rpush(name, values) :表示从右向左操作
# 2 rpush(name, values) 表示从右向左操作 conn.rpush('girls','古力娜扎')
结果:
3. lpushx(name, value) :只有key存在,才能追加
# 3 lpushx(name, value) 只有key存在,才能追加 conn.lpushx('girls','杨幂') conn.lpushx('boys','yyqx') # Redis没有任何变化,因为boys不存在
结果:
4. rpushx(name, value) 表示从右向左操作
# 4 rpushx(name, value) 表示从右向左操作 ,name值存在,才会增加值 conn.rpushx('girls','方圆') conn.rpushx('boys','whd')
结果:
5. llen(name):name对应的list元素的个数
# 5 llen(name) # name对应的list元素的个数 print(conn.llen('girls'))
结果:
Redis:
6. linsert(name, where, refvalue, value)):在name对应的列表的某一个值前或后插入一个新值
# 6 linsert(name, where, refvalue, value)) 在name对应的列表的某一个值前或后插入一个新值 # refvalue:列表中的值,value:将被插入的新值,where:插在哪(前/后) conn.linsert('girls',where='before',refvalue='刘亦菲',value='赵露思') conn.linsert('girls',where='after',refvalue='刘亦菲',value='赵今麦')
结果:
7.r.lset(name, index, value):将name对应的list的某个索引位置重新赋值
# 7 r.lset(name, index, value) # 对某个索引位置的值,重新赋值 conn.lset('girls',0,'ooo')
结果:
8. r.lrem(name, num, value)
# 8 r.lrem(name, num, value) # num=0,删除列表中所有的指定值 conn.lrem('girls',1,'刘亦菲') # 从左侧删一个,写几个就会删几个指定的值 conn.lrem('girls',-1,'刘亦菲') # 从右侧删一个 conn.lrem('girls',0,'刘亦菲') # 全删除
9. lpop(name)
# 9 lpop(name) print(conn.lpop('girls')) # 左侧弹出一个
结果:
10.rpop(name)
# 10 rpop(name) 表示从右向左操作 print(conn.rpop('girls')) # 右侧弹出
结果:
11. lindex(name,index):在name对应的列表中根据索引获取列表元素
# 11 lindex(name, index) print(conn.lindex('girls',0))
结果:
12.lrange(name,start,end):在name对应的列表分片获取数据
# 12 lrange(name, start, end) print(conn.lrange('girls',1,4)) # 前后都是闭区间
结果:
补充:一次性把列表中数据都取出来
import redis conn = redis.Redis(decode_responses=True) # 一次性把列表中数据都取出来 print(conn.lrange('girls',0,-1)) # -1是从右开始的第一位 print(conn.lrange('girls',0,conn.llen('girls'))) conn.close()
结果:
五、Redis操作之Hash操作
1.hset(name, key, value) :设置hash值
# 1 hset(name, key, value) #设置hash值 conn.hset('userinfo', 'name', 'hh') conn.hset('userinfo', 'age', '19')
结果:
2. hmset(name, mapping) :弃用了,统一用hset
# 2 hmset(name, mapping) 弃用了,统一用hset conn.hmset('userinfo2',{'name':'pyy',"age":33}) conn.hset('userinfo3',mapping={'name':'xxx',"age":33})
结果:
3. hget(name,key):获取name中某个key对应的值
# 3 hget(name,key) # 获取name中某个key对应的值 print(conn.hget('userinfo','name'))
结果:
4. hmget(name, keys, *args) :获取值
# 4 hmget(name, keys, *args) 获取值 print(conn.hmget('userinfo',['name','age'])) print(conn.hmget('userinfo','name','age'))
结果:
5. hgetall(name):一次性取出所有name的值
# 5 hgetall(name) # 慎用---》userinfo 对应的value值非常多,一次性拿出来,很耗时 print(conn.hgetall('userinfo'))
结果:
6. hlen(name)
# 6 hlen(name) print(conn.hlen('userinfo'))
结果:
7. hkeys(name) :取出name所有的key值
# 7 hkeys(name) 取出name所有的key值 print(conn.hkeys('userinfo'))
结果:
8. hvals(name):取出name中所有的value值
# 8 hvals(name) 取出name中所有的value值 print(conn.hvals('userinfo'))
结果:
9. hexists(name, key): 判断name中是否存在这个key值
# 9 hexists(name, key) 判断name中是否存在这个key值 print(conn.hexists('userinfo','hobby'))
结果:
10. hdel(name,*keys) :删除key值
# 10 hdel(name,*keys) 删除key值 # conn.hdel('userinfo',['name','age']) # 不支持传列表 conn.hdel('userinfo','name','age')
结果:
11. hincrby(name, key, amount=1) :让name中的某个key对应的值自动加1
# 11 hincrby(name, key, amount=1) 让name中的某个key对应的值自动加1 print(conn.hget('userinfo2','age')) conn.hincrby('userinfo2','age') print(conn.hget('userinfo2','age'))
结果:
12 hincrbyfloat(name, key, amount=1.0) :让name中的某个key对应的value值增加,amount是浮点型
13. hscan(name, cursor=0, match=None, count=None) :不单独用,取出部分数据
import redis conn = redis.Redis(decode_responses=True) # 13 hscan(name, cursor=0, match=None, count=None) # 不单独用, ## 造数据 for i in range(1000): conn.hset('hash2','egg_%s'%i,'鸡蛋%s号'%i) # count 数字是大致的 大小,如果拿了10 ,可能是9 可能是11 res=conn.hscan('hash2',cursor=0,count=10) # hash是无序,所以不是从egg_0开始的 print(len(res[1])) conn.close()
结果:
14. hscan_iter(name, match=None, count=None) :替代hgetall,一次性全取出值,如果占内存很大,会有风险 , 使用hscan_iter 分批获取值,内存占用很小
import redis conn = redis.Redis(decode_responses=True) # 14 hscan_iter(name, match=None, count=None) # 替代hgetall,一次性全取出值,如果占内存很大,会有风险 , 使用hscan_iter 分批获取值,内存占用很小 for item in conn.hscan_iter('hash2',count=10): print(item) conn.close()
Redis通用操作
1. delete(*names):删除对应的name
# 1. delete(*names) # 删除对应的name ----》对应的命令是:DEL(大小写都行) conn.delete('userinfo2') # 删除userinfo2
2. exists(name):判断name是否存在,返回值为:0/1
# 2. exists(name):判断name是否存在,返回值为:0/1 print(conn.exists('userinfo2'))
3. keys(pattern='*'):找出pattern对应的key值,*号表示拿出所有
# 3.keys(pattern='*'):找出pattern对应的key值,*好表示拿出所有 print(conn.keys('user*')) # 拿出到名字中带user的key值 print(conn.keys('*')) # 拿出所有 print(conn.keys()) # 拿出所有
结果:
4. expire(name,time):给对应的name设置过期时间,以秒为单位
# 4. expire(name ,time):给对应的name设置过期时间,以秒为单位 conn.expire('hash2',5)
5. rename(src, dst):给已存在的key值,重新命名
# 5. rename(src, dst):给已存在的key值,重新命名 conn.rename('gender','gen')
6. move(name, db)):将name移到其他的表中,db写几就是哪个表
# 6. move(name, db)):将name移到其他的表中,db写几就是哪个表 conn.move('name',2)
结果:
7. randomkey():随机拿出一个key
# 7. randomkey():随机取出key print(conn.randomkey())
结果:
8. type(name):name对应的类型
# 8. type(name):name对应的类型 print(type('name'))
结果: