Redis

Redis介绍与安装

redis 缓存数据库, 大部分时间做缓存,不仅仅可以做缓存。

非关系型数据库

C语言写的服务,用来存储数据,数据存在内存中,取值,存值速度都非常快。

redis快的原因

1.纯内存操作

2.网络模型使用的IO多路复用(可以处理的请求数更多)

  1. 6.x 版本之前,是单进程单线程架构,没有线程进程间的切换,消耗的资源更少。

官网下载

源码包安装,不支持windos系统

redis.io/download/
redis.cn/download.html  #中文网站

安装

mac  源码编译安装
linux 源码编译安装
windows  因epoll模型无法安装,但微软基于源码改动编译成了安装包

windows下载地址

下载msi文件

# 最新5.x版本
https://github.com/tporadowski/redis/releases/
# 最新3.x版本
https://github.com/microsoftarchive/redis/releases

image

image

安装完成后会释放两个命令,执行完毕会自动加到服务里

redis-server  # 类似 mysqld 服务端启动
redis-cli    # 类似 mysql 客户端启动

安装目录需要注意的文件

redis-server
redis-cli
redis.windows-service.conf 配置文件
	-bind  127.0.0.1 # 服务跑在的地址
	-port  6379    #监听的端口

启动redis

1. 服务中点击启动
 	后台启动
2. 使用命令
	redis-server 指定配置文件 不指定 默认

客户端连接redis

1  命令
	redis-cli  # 默认连接本地6379端口
2  远程连接方式
   redis-cli -h 127.0.0.1 -p 端口

存储方式

key : value形式存储,没有表

图形化客户端操作

可以百度搜

下载

Redis Desktop Manager 原来免费,现在收费了

https://www.52pojie.cn/forum.php?mod=viewthread&tid=1699654

图形化工具连接redis服务器

image

进入可以看到一共有16个库,但是我们只用一个db0. 可以在配置文件中设置产生库的数量。

python连接redis

下载模块

pip install redis

导入模块

from redis import Redis

实例化得到对象

conn=Redis(host='127.0.0.1',port=6379)
参数:
db=0               # 指定库
socket_timeout = None  # 超时时间 
encoding='utf-8'      # 编码

设置值

conn.set('name','lxj')

使用conn对象操作redis

# 获取值
res=conn.get('name')  # 返回的数据时bytes格式
print(res)

关闭

conn.close()

代码


# 1.导入模块
from redis import Redis

# 2.实例化得到对象
conn = Redis(host='127.0.0.1',port=6379)

# 3.操作redis
res = conn.get('name')
print(res)

# 4 设置值
ret =conn.set('age',19)


# 5.关闭链接
conn.close()

链接池链接

多线程情况下链接是取链接池的链接与redis操作,目的为了不创建太多的链接数。

补充

django mysql 默认不带链接池一个请求就是一个mysql连接

如果使用链接池的话可能会有问题,并发数过高,导致mysql连接数过高,影响mysql性能

django连接池相关文档

https://blog.51cto.com/liangdongchang/5140039

不使用链接池链接redis

import redis
from redis import Redis
from threading import Thread

def task():
    # 实例化得到对象
    conn = Redis(host='127.0.0.1',port=6379)
    print(conn.get('name'))

# 开100个线程
for i in range(100):
    t=Thread(target=task)  # 每次都是一个新链接,会导致redis的链接数过多
    t.start()

使用链接池

import redis
from threading import Thread

# 使用redis链接池
"""
max_connections =    # 池的大小
"""
# 创建10个链接
POLL = redis.ConnectionPool(max_connections=10,host='127.0.0.1',port=6379)
def task():
    # 从池中拿一个链接
    conn = redis.Redis(connection_pool=POLL)  # 会报错,线程过多池里链接不够。有一个参数可以设置等待时间( 后面再说 )
    print(conn.get('name'))

# 开10个线程
for i in range(10):
    t=Thread(target=task)
    t.start()

把POLL做成单例性能更高,否则有可能在每一个线程中创建一个池,那就是10个线程x10个池,性能更低。要保证只有一个线程池

单例模式多线程链接池链接

创建一个py文件创建链接池

import redis
# 创建10个链接
POLL = redis.ConnectionPool(max_connections=10,host='127.0.0.1',port=6379)

导入使用

import redis
from threading import Thread
# 导入单例
from pool import POLL


def task():
    # 从池中拿一个链接
    conn = redis.Redis(connection_pool=POLL)
    print(conn.get('name'))

# 开10个线程
for i in range(10):
    t=Thread(target=task)  
    t.start()

Redis数据类型(value类型)

1.字符串 常用来做缓存 ,计数

2.列表 简单的消息队列

3.字典 (hash) 缓存

4.集合 去重

5.有序集合 常用来做排行榜

Redis之字符串类型

redis 是key-value形式存储,数据放在内存中,如果断电那么数据会丢失。 redis有持久化方案。

  • Redis提供了不同的持久性选项:
    • RDB
    • AOF

相关文档

https://www.cnblogs.com/wen-xin/p/11838603.html

字符串操作

set 改值
set(name, value, ex=None, px=None, nx=False, xx=False)
"""
ex = 过期时间(秒)
px = 过期时间(毫秒)
nx = True name存在set不会执行   nx=False 就会修改  不填则都会执行
xx = True hobby存在才会修改,不存在则不修改,xx=False hobby 不存在也会会新增
"""
# 存储一个爱好,3秒过期
conn.set('hobby','raper',ex=3)
# 3000毫秒过期
conn.set('hobby','raper',px=3000)
# name字段已存在 nx为True则不会修改内容
conn.set('name','lxj',nx=True)
# nx=False 就会修改
conn.set('name','lxj',nx=False)
# xx=Ture hobby存在才会修改,不存在则不修改
conn.set('hobby','篮球',xx=True)
# xx=False hobby 不存在也会会新增
conn.set('hobby','上网',xx=False)
conn.close()
get 取值
get(name)
# 取出来是bytes格式,以字节为单位
conn.get('name')
# 强转字符串
str(conn.get('name'),encoding='utf-8')
strlen 统计长度
strlen(name)
# 统计字节长度
conn.strlen('hobby')
incr 自增
incr(self,name,amount=1)
# 自增 不传默认1
conn.incr('age')

incrby 同样的功能
了解
1.setnx(name,value)
等同于 conn.set('name','lxj',nx=True)
# 字段存在不会修改
conn.setnx('name','刘亦菲')

2.setex(name,value,time)
等同于conn.set('wife','牛',ex=3)
# 3秒后过期,中间参数是时间
conn.setex('wife',3,'牛牛牛')


3.mset(*args,**kwargs)
# 传字典,批量设置值
conn.mset('wife':'牛牛牛','hobby':'小动物')

4.mget(keys,*args)
# 批量获取值,一次可以取多个拿出来是个列表
conn.mget('name','wife')

5.getset(name,value)
# 把第一个参数的值拿出来res接收的是这个值,并把redis库中的hobby值换成value
res=conn.getset('hobby','打篮球')

6.getrange(key,start,end)
# 范围内取值,以字节为单位的长度,字节不够拿一个字符则报错
conn.getrange('wife',0,2)

7.setrange(name,offset,value)
# 从第二个字节开始插入bbb
conn.setrange('wife',2,'bbb')

比特位操作
setbit(name,offset,value)
getbit(name,offset)
bitcount(key,start=None,end=None)

8 incrbyfloat(self,name,amount=1.0)
# 自增小数,数字精度不高
conn.incrbyfloat('age',1.2)

9 decr(self,name,amount=1)
decrby同样功能
# 自减1 不能带小数
conn.decrby('age')

10.append(key,value)
# 在原本hobby的值后面加上sb
conn.append('hobby','sb')

redis数据类型之列表(value)

列表操作

1 lpush记住
lpush(name,value)
# l list缩写, 从左侧插入 第二个会把第一个抵过去所以就是第一个位置
conn.lpush('girs','lyf','迪丽热巴')
2.rpush
rpush(name,value)
# 从右侧插  最后
conn.rpush('girs','小红')
3.lpushx
lpushx(name,value)
# 有boys才会存,没有不存 左侧插入
conn.lpushx('boys','hg')
4.rpushx
rpushx(name,value)
# # 有boys才会存,没有不存 右侧插入
conn.lpushx('boys','wg')
5.llen记住
llen(name)
# 统计数据个数
res = conn.llen('girls')
print(res)
6.linsert
linsert(name,where,refvlue,value)
# 在迪丽热巴前面插进古力娜扎
conn.linsert('girls','before','迪丽热巴','古力娜扎')
# 在小红后面插上小绿
conn.linsert('girls','after','小红','小绿')
"refvlue参照数据必须有值才能插入"
  1. lset
lset(name,index,value)
#把索引位1的数据修改成小黑
conn.lset('girs',1,'小黑')
8 lrem
lrem(name,num,value)
# 从左侧 删除1个xxx 负数从右侧开始删 0全删除
conn.lrem('girls',1,'xxx')
9 lpop记住
lpop(name)
# 左侧弹出    rpop 右侧弹
res = conn.lpop('girls')
  1. lindex
lindex(name,index)
# 拿出索引位1的数据
res =conn.lindex('girls',1)
12 lrange记住
lrange(name,start,end)
# 拿出从索引位0开始到索引位1的数据
res = conn.lrange('girls',0,1)
13 ltrim
ltrim(name,start,end)
# 只剩第二个位置到第四个位置,索引位
conn.ltrim('girls',2,4)
14 rpoplpush
rpoplpush(src,dst)
#从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
"""
src,要取数据的列表的name
dst,要添加数据的列表的name
"""
conn.rpoplpush('girls','boys')
15 blpop
blpop(key,timeout)
# 左侧有值弹出,没值阻塞,等待有值(链接的同一个redis数据库不分机器)插入就弹出
conn.blpop('boys')

"""简单的消息队列,程序崩了数据没处理完会丢失"""


  1. brpop
与上个同样从右边开始
17. brpoplpush
# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
 
参数:
src,取出并要移除元素的列表对应的name
dst,要插入元素的列表对应的name
timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞

redis数据类型之字典(hash)(value值)

字典操作

hset记住
hset(name, key, value)
# 创建一个userinfo 里有name:lqz ,如果存在则修改值
conn.hset('userinfo','name','lqz')
conn.hset('userinfo',mapping={'name':'lxj','age':18})
hget记住
hget(name,key)
# 获取userinfo的name对应的值
res=conn.hget('userinfo','name')
print(res)
hmget记住
hmget(name, keys, *args)
# 可以一次获取多个k对应的值
res=conn.hmget('userinfo',['name','age'])
res=conn.hmget('userinfo','name','age')
print(res)
hgetall(慎用)
hgetall(name, keys, *args)
# 获取name对应hash的所有键值,数据量过大可能会撑爆内存
res=conn.hgetall('userinfo')
print(res)

hlen记住
hlen(name)
# 获取name对应的hash中键值对的个数
res=conn.hlen('userinfo')
print(res)
hkeys
hkeys(name)
# 获取name对应的hash中所有的key的值
res=conn.hkeys('userinfo')
print(res)
hvals
hvals(name)
# 获取name对应的hash中所有的value的值
res=conn.hvals('userinfo')
print(res)
hexists
hexists(name, key)
# 检查name对应的hash是否存在当前传入的key,存在返回True 否则False
res=conn.hexists('userinfo','name')
print(res)
hdel记住
hdel(name,\*keys)
# 将userinfo里的age键值对删掉,返回0或1
res=conn.hdel('userinfo','age')
print(res)
hincrby
hincrby(name, key, amount=1)
# 将userinfo里age对应的值自增1
res=conn.hincrby('userinfo','age',1)
print(res)
hincrbyfloat
hincrbyfloat(name, key, amount=1.0)
# 自增小数
hscan
hscan(name, cursor=0, match=None, count=None)
# 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
 
# 参数:
    # 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记住
hscan_iter(name, match=None, count=None)
# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# count还不知道有啥用
res=conn.hscan_iter('userinfo',count=1)
for i in res:
    print(i)
conn.close()

redis其他操作

通用操作

delete
delete(*names)
# 删除数据 删除userinfo
conn.delete('userinfo')
# 删除userinfo,userinfo2
conn.delete(*['userinfo','userinfo2'])
exists
exists(name)
# 判断是否存在  返回1或0
conn.exists('userinfo')
keys
keys(pattern='*')
# 拿出库中所有k
conn.keys('*')
# 含有t的
conn.keys('*t')

"*表示多个字符,?表示一个字符"
expire
expire(name,time)
# userinfo 3秒过期
conn.expire('userinfo',3)
rename
rename(src,dst)
# hobby改名成hobby111
conn.rename('hobby','hobby111')
move
move(name,db)
# 把hobby移到8库中
conn.move('hobby',8)
randomkey
randomkey()
# 随机弹出一个k
res=conn.randomkey()
type
type(name)
# 查看hobby的数据类型
conn.type('hobby')

redis数据类型操作详细博客

https://www.cnblogs.com/liuqingzheng/p/9833534.html

redis管道

redis单实例并基于管道才能支持事物.(单实例才能用管道)

测试代码

import redis
conn= redis.Redis()
# 张三金额减100
conn.decr('zhangsan_je',100)
raise Exception('程序崩溃了')
# 李四金额加一百
conn.incr('lisi_je',100)
conn.close()

"程序中间崩了,张三钱扣了,李四没加钱"

# 管道
import redis
conn= redis.Redis()
# pipeline管道,transaction=True开启事物
p= conn.pipeline(transaction=True)

p.multi()
# 张三金额减100
p.decr('zhangsan_je',100)
raise Exception('程序崩溃了')
# 李四金额加一百
p.incr('lisi_je',100)

p.execute()
conn.close()
"程序崩了会都不会有变化"
posted @ 2023-03-07 19:03  李阿鸡  阅读(15)  评论(0编辑  收藏  举报
Title