redis 基础1(包含介绍,安装)
Redis介绍安装
# 关于redis -1.redis是一个缓存型数据库【大部分时间做缓存,但是不仅仅可以做缓存】 -2.redis是一个非关系型(nosql)数据库【区别于mysql】 -3.redis是c语言写的服务,用来存储数据,数据是存储到内存中,取值,放值速度非常快,10w qps # 面试题:redis为什么这么快 -1.纯内存操作 -2.网络模型使用的IO多路复用(epoll)(可以处理的请求数更多) -3.6.x之前,单进程,单线程架构,没有鲜葱进程间切换,更少的消耗资源 # redis使用 key-value的形式存储,没有表的概念 # 版本问题 最新的:7.x 公司里:5.x比较多 # 安装 - mac 源码编译安装 - linux 源码编译安装 - win 微软自己,基于源码改动编译为安装包 5.x 版本:https://github.com/tporadowski/redis/releases/ 3.x 版本:https://github.com/microsoftarchive/redis/releases - 一路下一步即可,安装完cmd执行两个命令,把redis自动添加到服务中 redis-server 服务端的启动命令 mysqld redis-cli 客户端的启动命令 mysql # 安装后的目录 redis-server redis-cli redis.window-service.conf 配置文件 -bind 127.0.0.1 # 服务跑的地址 -port 6379 # 监听的端口 # 启动redis 1.方式一: -在服务中,点击启动,后台启动 2.方式二: -redis-server 指定配置文件,不指定会按默认的 # 客户端连接redis 1.方式一 -redis-cli # 默认连接本地的6379端口 2.方式二 -redis-cli -h 地址 -p 端口 3.方式三 - 使用图形化客户端操作 -1.Redis Desktop Manager:
开源,现在收费,老版本免费(推荐) -> 底层使用Qt5,qt是个平台,专门用来图形化界面的 -> 可以使用c++写 -> 可以使用python写 pyqt5 使用python写图形化界面 (少量公司再用) -2.Redis Client:
小众 - 图形化界面,连接redis 输入地址和端口,点击连接即可 # redis默认有16个库,默认连进去就是第0个
Redis普通连接和连接池
# python 相当于客户端,操作redis # 安装模块: pip install redis # 补充: django中操作mysql,没有连接池的,一个请求就是一个mysql连接 - 可能存在问题 并发数过高,可能导致mysq'l连接数过高,进而影响mysql性能 - 使用django连接池: https://blog.51cto.com/liangdongchang/5140039
普通连接
# 1.安装redis模块 pip install redis # 2.导入模块的Redis类 from redis import Redis # 3.实例化得到对象 coon =Redis(host='127.0.0.1',port=6379) # 4.使用conn,操作redis - 获取name的值 ->res=conn.get('name') # 返回的数据是bytes格式 # 5.设置值 conn.set('age',19) conn.close()
连接池连接
###1.创建一个pool.py import redis # 创建一个大小为10的redis连接池 POOL = redis.ConnectionPool(max_connections=10,host='127.0.0.1',port=6379) ###2.测试代码 import redis from threading import Thread from pool import POOL def task(): # 做成模块后,导入,无论导入多少次,导入的都是那一个POOL对象 conn = redis.Redis(connection_pool=POOL) # 报错的原因是拿连接,连接池里不够了,没有等待,线程会报错,需要设置等待,参数 print(conn.get('name')) for i in range(10000): # 每次都是一个新的连接,会导致连接池的连接数过多 t=Thread(target=task) t.start() ### 单例模式 -1.单例模式是一种设计模式【设计模式共有23种】 - 全局只有一个 这个对象 p1=Person() # p1 对象 p2=Person() # p2 新对象 - 单例模式的六种方式...
Redis字符串类型
# 1.redis 是key-value形式存储 # 2.redis 数据放在内存中,如果断电,数据丢失 - 需要有持久化的方案 # 3.redis有5种数据类型【value类型】 - 字符串:用的最多,做缓存;做计数器 - 列表: 简单的消息队列 - 字典(hash):缓存 - 集合:去重 - 有序集合:排行榜 #字符串类型使用
''' 1 set(name, value, ex=None, px=None, nx=False, xx=False) 2 setnx(name, value) 3 setex(name, value, time) 4 psetex(name, time_ms, value) 5 mset(*args, **kwargs) 6 get(name) 7 mget(keys, *args) 8 getset(name, value) 9 getrange(key, start, end) 10 setrange(name, offset, value) 11 setbit(name, offset, value) 12 getbit(name, offset) 13 bitcount(key, start=None, end=None) 14 bitop(operation, dest, *keys) 15 strlen(name) 16 incr(self, name, amount=1) # incrby 17 incrbyfloat(self, name, amount=1.0) 18 decr(self, name, amount=1) 19 append(key, value) ''' import redis conn = redis.Redis() # 1 set(name, value, ex=None, px=None, nx=False, xx=False) # ex,过期时间(秒) # px,过期时间(毫秒) # nx,如果设置为True,则只有name不存在时,当前set操作才执行, 值存在,就修改不了,执行没效果 # xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值 # conn.set('hobby','篮球',ex=3) # conn.set('hobby','篮球',px=3) # conn.set('name','lqz',nx=True) # conn.set('name','lqz',nx=False) # conn.set('hobby','篮球',xx=True) # conn.set('hobby','篮球',xx=False) # redis---》实现分布式锁,底层基于nx实现的 # 2 setnx(name, value) # 等同于:conn.set('name','lqz',nx=True) # conn.setnx('name', '刘亦菲') # 3 setex(name, value, time) # 等同于:conn.set('name','lqz',ex=3) # conn.setex('wife', 3, '刘亦菲') # 4 psetex(name, time_ms, value) # conn.psetex('wife',3000,'刘亦菲') # 5 mset(*args, **kwargs) # conn.mset({'wife': '刘亦菲', 'hobby': '篮球'}) # 6 get(name) # print(str(conn.get('wife'),encoding='utf-8')) # print(conn.get('wife')) # 7 mget(keys, *args) # res=conn.mget('wife','hobby') # res=conn.mget(['wife','hobby']) # print(res) # 8 getset(name, value) # res=str(conn.getset('wife','迪丽热巴'),encoding='utf-8') # res=conn.getset('wife','迪丽热巴') # print(res) # 9 getrange(key, start, end) # res = str(conn.getrange('wife', 0, 2), encoding='utf-8') # 字节长度,不是字符长度 前闭后闭区间 # print(res) # 10 setrange(name, offset, value) # conn.setrange('wife',2,'bbb') # ---- 比特位---操作 # 11 setbit(name, offset, value) # 12 getbit(name, offset) # 13 bitcount(key, start=None, end=None) # ---- 比特位---操作 # 14 bitop(operation, dest, *keys) 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值 # 15 strlen(name) # res=conn.strlen('hobby') # 统计字节长度 # print(res) # 16 incr(self, name, amount=1) # 自增,不会出并发安全问题,单线程架构,并发量高 # conn.incr('age')
# # incrby
# 17 incrbyfloat(self, name, amount=1.0) # conn.incrbyfloat('age',1.2) # 18 decr(self, name, amount=1) # conn.decrby('age') # conn.decrby('age',-1) # 19 append(key, value) # conn.append('hobby','sb') print(conn.strlen('hobby')) conn.close() ''' 重要的: set get strlen 字节长度 incr '''
Redis列表类型
""" 1. lpush(name,values) 2. rpush(name,values) # 表示从右向左操作 3. lpush(name,values) 4. rpushx(name,values) # 表示从右向左操作 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.linedx(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) """
import redis conn = redis.Redis(host='127.0.0.1',port=6379)
# 1 lpush(name, values) # 从左侧插入 conn.lpush('girls', '刘亦菲', '迪丽热巴') conn.lpush('girls', '周淑怡') # 2 rpush(name, values) # 表示从右向左操作 conn.rpush('girls', '小红') # 3 lpushx(name, value) conn.lpushx('boys','小刚') conn.lpush('boys','小刚') conn.lpushx('girls','小刚') # 4 rpushx(name, value) # 表示从右向左操作 # 5 llen(name) res = conn.llen('girls') print(res) # 6 linsert(name, where, refvalue, value)) conn.linsert('girls','before','迪丽热巴','古力娜扎') conn.linsert('girls', 'after', '小红', '小绿') conn.linsert('girls', 'after', '小黑', '小嘿嘿') # 没有标杆,插入不进去 # 7 r.lset(name, index, value) # 按位置改值 conn.lset('girls',1,'xxx') # 8 r.lrem(name, value, num) conn.lrem('girls',1,'xxx') # 从左侧开始,删除1个 conn.lrem('girls',-1,'xxx') # 从右侧开始,删除1个 conn.lrem('girls',0,'xxx') # 从左开始,全删除 # 9 lpop(name) res=conn.lpop('girls') print(res) # 10 rpop(name) 表示从右向左操作 # 11 lindex(name, index) res = str(conn.lindex('girls', 1), encoding='utf-8') print(res) # 12 lrange(name, start, end) res=conn.lrange('girls',0,0) # 前闭后闭区间 print(res) # 13 ltrim(name, start, end) conn.ltrim('girls',2,3) # 14 rpoplpush(src, dst) # 15 blpop(keys, timeout) # 记住 ,可以做消息队列使用 阻塞式弹出,如果没有,就阻塞 res=conn.blpop('boys') print(res) # 16 r.brpop(keys, timeout) # 从右向左获取数据 # 17 brpoplpush(src, dst, timeout=0)
conn.close() ## 重要的 ''' 1. lpush 2. lpop 3. llen 4. lrange '''
Redis之hash类型
""" 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. vals(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) """
import redis conn = redis.Redis(host='127.0.0.1',port=6379)
# 1 hset(name, key, value) conn.hset('userinfo','name','lqz') conn.hset('userinfo',mapping={'age':19,'hobby':'篮球'}) # 2 hmset(name, mapping) # 批量设置,被弃用了,以后都使用hset conn.hmset('userinfo2',{'age':19,'hobby':'篮球'}) # 3 hget(name,key) res=conn.hget('userinfo','name') print(res) # 4 hmget(name, keys, *args) res=conn.hmget('userinfo',['name','age']) res = conn.hmget('userinfo', 'name', 'age') print(res) # 5 hgetall(name) # 慎用 res=conn.hgetall('userinfo') print(res) # 6 hlen(name) res=conn.hlen('userinfo') print(res) # 7 hkeys(name) res=conn.hkeys('userinfo') print(res) # 8 hvals(name) res=conn.hvals('userinfo') print(res) # 9 hexists(name, key) res = conn.hexists('userinfo', 'name') res = conn.hexists('userinfo', 'name1') print(res) # 10 hdel(name,*keys) res = conn.hdel('userinfo', 'age') print(res) # 11 hincrby(name, key, amount=1) conn.hincrby('userinfo', 'age', 2) # article_count ={ # '1001':0, # '1002':2, # '3009':9 # } # 12 hincrbyfloat(name, key, amount=1.0) # hgetall 会一次性全取出,效率低,可以能占内存很多 # 分批获取,hash类型是无序 # 插入一批数据 for i in range(1000): conn.hset('hash_test','id_%s'%i,'鸡蛋_%s号'%i) res=conn.hgetall('hash_test')
# 可以,但是不好,一次性拿出,可能占很大内存 print(res)
# 13 hscan(name, cursor=0, match=None, count=None) # 它不单独使用,拿的数据,不是特别准备 res = conn.hscan('hash_test', cursor=0, count=5) print(len(res[1])) #(数字,拿出来的10条数据) 数字是下一个游标位置 # 咱们用这个,它内部用了hscan,等同于hgetall 所有数据都拿出来,count的作用是,生成器,每次拿count个个数 # 14 hscan_iter(name, match=None, count=None) res=conn.hscan_iter('hash_test',count=10) print(res) # generator 只要函数中有yield关键字,这个函数执行的结果就是生成器 ,生成器就是迭代器,可以被for循环 for i in res: print(i)
conn.close()
'''
1.hset
2.hget
3.hmget
4.hlen
5.hdel
6.hscan_iter 获取所有值,但是省内存 等同于hgetall
'''
Redis其他操作
''' 通用操作,不指定类型,所有类型都支持 1.delete(*names) 2.exists(name) 3.keys(pattern='*') 4.expire(name ,time) 5.rename(src, dst) 6.move(name, db)) 7.randomkey() 8.type(name) ''' import redis conn = redis.Redis()
# 1 delete(*names) conn.delete('name', 'userinfo2') conn.delete(['name', 'userinfo2']) # 不能用它 conn.delete(*['name', 'userinfo2']) # 可以用它 # 2 exists(name) res=conn.exists('userinfo') print(res) # 3 keys(pattern='*') res=conn.keys('w?e') # ?表示一个字符, * 表示多个字符print(res) # 4 expire(name ,time) conn.expire('userinfo',3) # 5 rename(src, dst) conn.rename('hobby','hobby111') # 6 move(name, db)) conn.move('hobby111',8) # 7 randomkey() res=conn.randomkey() print(res) # 8 type(name) print(conn.type('girls')) print(conn.type('age'))
conn.close()
Redis管道
# 事务的四大特性 原子性/一致性/隔离性/持久性 # redis支持事务吗? 单实例才支持所谓的事物,支持事务是基于管道的 - 执行命令 一条一条执行,以转账为例: """ 张三 金额 -100 conn.decr('zhangsan_je',100) 程序中途挂了 raise("挂了") 你 金额并没有+100 conn.incr('lisi_je',100) """ - 把这两条命令,放到一个管道中,先不执行,执行excute,一次性都执行完成 """ conn.decr('zhangsan_je',100) conn.incr('李四_je',100) """ # 使用方法: import redis conn = redis.Redis() p=conn.pipeline(transaction=True) p.multi() p.decr('zhangsan_je', 100) # raise Exception('崩了') p.incr('lisi_je', 100) p.execute() conn.close()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律