Redis介绍和安装
文档:www.cnblogs.com/liuqingzhen…
介绍
1.Redis:开源软件,存储数据的,速度非常快,redis是一个key-value存储系统(没有表的概念),是cs架构的软件
ps:服务端 客户端(eg:python,java,go,图形化界面,命令窗口的命令)
2.关系型数据库和非关系型数据库
1.关系型:mysql,PostgreSQL,oracle,sqlserver,db2
-PG
"""
去IOE:国产化
IBM--->浪潮信息,曙光,联想
Oracle--->数据---->达梦。。。。
EMC存储-->国产存储
"""
2.非关系型数据库(nosql):redis(缓存),mongodb(json文档数据存储),es(大数据量存储)
ps:nosql 指非关系型数据库: no only sql,对关系型数据库的补充
3.redis特点:
1.开源软件,存数据,cs架构
2.key-value存储 ,5大数据类型 value的类型是5种:字符串,hash(字典),列表,集合,有序集合
3.速度快:
1.纯内存存储(核心)
2.使用了IO多路复用的网络模型
3.数据操作是单线程,避免了线程间切换,而且没有锁,也不会数据错乱(避免了加锁和线程间切换的消耗)
4.支持持久化
1.纯内存,可以存到硬盘上,防止数据丢失
5.redis又被称之为 缓存数据库
安装
1.redis 是用c语言编写的,需要在不同平台编译成可执行文件,才能在这个平台上运行
2.redis 使用了io多路复用种的epoll模型,win不支持epoll
1.redis官方,不支持win版本
2.微软官方,就把redis改动,编译成可执行,能运行在win上,滞后 3.x版本
3.第三方:5.x版本
3.下载路径:
redis 官方网:https://redis.io/download/
redis中文网:http://redis.cn
win:3.x:https://github.com/microsoftarchive/redis/releases
win:5.x:https://github.com/tporadowski/redis/releases/
4.安装:一路下一步
1.安装完成后,在安装路径下有
1.redis-cli.exe # mysql
2.redis-server.exe # mysqld
3.redis.windows-service.conf # my.ini
2.并且会自动做成服务
服务的命令:redis-server.exe redis.windows-service.conf
5.启动redis服务端
1.命令行中redis就可以启动服务:redis-server
2.命令行中,启动服务,并指定配置文件
redis-server 配置文件路径
3.使用服务启动
6.客户端连接
1.命令行客户端:
redis-cli # 默认连本地的6379端口
redis-cli -p 6379 -h 127.0.0.1 # Redis服务器在远程主机上运行或使用了非默认端口
2.图形化客户端链接
1.最新版的Navicate支持链接redis了(收费的)
2.Redis Desktop Manager(https://resp.app/),收费的,用的多 qt写图形化界面
qt是个平台,做GUI[图形化界面]开发
用c写,用python写 pyqt5
3.python的模块
-pip install redis
redis操作
前提:前往一个方便管理redis持久化文件的逻辑再启动服务:dump.rdb
1)前台启动服务
>: redis-server
2)后台启动服务
>: redis-server --service-start
注)Linux系统后台启动(或是修改配置文件,建议采用方式)
>: redis-server &
3)配置文件启动前台服务
>: redis-server 配置文件的绝对路径
4)配置文件启动后台服务
注)windows系统默认按Redis安装包下的redis.windows-service.conf配置文件启动
>: redis-server --service-start
注)Linux系统可以完全自定义配置文件(redis.conf)后台启动
>: redis-server 配置文件的绝对路径 &
"""
windows系统
1)前台启动
i)打开终端切换到redis安装目录
>: cd C:\Apps\Redis
ii)启动服务
>: redis-server redis.windows.conf
2)后台启动
i)打开终端切换到redis安装目录
>: cd C:\Apps\Redis
ii)启动服务(后面的配置文件可以省略)
>: redis-server --service-start redis.windows-service.conf
"""
redis普通连接和连接池
普通连接
from redis import Redis
# conn=Redis() # 建立redis的连接
conn = Redis(
host = '127.0.0.1',
port = 6379,
db=0,
decode_responses=True) # 建立redis的链接 decode_responses=True,查询回来返回的结果是字符串类型,否则是byte格式
conn.set('name','nana')
res =conn.get('name')
print(res)
conn.close()
from redis import Redis
from threading import Thread
def task():
# conn=Redis() # 建立redis的连接
conn = Redis(
host = '127.0.0.1',
port = 6379,
db=0,
decode_responses=True) # 建立redis的链接 decode_responses=True,查询回来返回的结果是字符串类型,否则是byte格式
conn.set('name','nana')
res =conn.get('name')
print(res)
conn.close()
if __name__ == '__main__':
for i in range(1000):
t = Thread(target=task)
t.start()
连接池连接
import redis
from threading import Thread
from pool import POOL # 模块导入的方式, 天然单例
def task():
conn=redis.Redis(connection_pool=POOL) # 以后拿到链接,是从POOL种取,如果没有可用的了,默认不阻塞,可以通过某个参数配置,设置阻塞等待
conn.set('age',18)
res = conn.get('age')
print(res)
conn.close()
if __name__ == '__main__':
for i in range(10):
t = Thread(target=task)
t.start()
redis字符串类型
set(name, value, ex=None, px=None, nx=False, xx=False)
"""
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
"""
conn.set('hobby','篮球')
conn.set('hobby','足球',ex=6) # 6秒后销毁
conn.set('hobby','网球',px=6000) # 6秒后销毁(毫秒)
conn.set('hobby','网球',nx=True)
conn.set('hobby','网球',xx=True)
setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
conn.setnx('hobby1', '篮球') # # 等同于conn.set('hobby', '篮球', nx=True)
setex(name, value, time)
# 设置值
# 参数:
# time,过期时间(数字秒 或 timedelta对象)
psetex(name, time_ms, value)
"""
设置值
参数:
time_ms,过期时间(数字毫秒 或 timedelta对象
"""
conn.psetex('name',6000,'cx') # 设置后,6秒后销毁
mset(*args, **kwargs)
"""
批量设置值
如:
mset(k1='v1', k2='v2')
或
mget({'k1': 'v1', 'k2': 'v2'})
"""
conn.mset({'name':'nana','height':180}) # 批量创建,# 跟一次次设置的区别是,少了网络交互的时间
get(name)
获取值
res = conn.get('name') # # utf-8 编码,一个中文占3个字节 GBK 编码,一个中文占2个字节
print(res) # b'nana'
mget(keys, *args)
"""
批量获取
如:
mget('k1', 'k2')
或
r.mget(['k3', 'k4'])
res1 = conn.mget('name','age')
"""
res2 = conn.mget(['name','age'])
print(res1)
print(res2)
getset(name, value)
设置新值并获取原来的值
res = conn.getset('name','lyf')
print(res) # b'nana'
getrange(key, start, end)
"""
获取子序列(根据字节获取,非字符)
参数:
# name,Redis 的 name
# start,起始位置(字节)
# end,结束位置(字节)
如: "刘亦菲" ,0-3表示 "刘"
"""
res = conn.getrange('name',0,1) # # 前闭后闭区间,拿的是字节,不是字符
print(res) # b'ly'
setrange(name, offset, value)
# 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
conn.setrange('name',2,"abd") # lyabd
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 对应的值中
strlen(name)
# 返回name对应值的字节长度(一个汉字3个字节)
res = conn.strlen('name')
print(res) # 5
incr(self, name, amount=1)
"""
1.自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
name,Redis的name
amount,自增数(必须是整数)
注:同incrby,做计数器。不会出现并非安全问题
"""
conn.incrby('height')
incrbyfloat(self, name, amount=1.0)
"""
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
name,Redis的name
amount,自增数(浮点型)
"""
conn.incrbyfloat('height')
decr(self, name, amount=1)
"""
自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
参数:
# name,Redis的name
# amount,自减数(整数)
"""
conn.decrby('height')
append(key, value)
"""
在redis name对应的值后面追加内容
参数:
key, redis的name
value, 要追加的字符串
"""
conn.append('name','xxxx')
Redis hash类型
hset(name, key, value)
"""
1.name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
2.参数:
name,redis的name
key,name对应的hash中的key
value,name对应的hash中的value
注:
hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
"""
conn.hset('userinfo','name','娜娜')
conn.hset('userinfo','age',18)
conn.hset('userinfo','gender','female')
hmset(name, mapping)
"""
1.在name对应的hash中批量设置键值对
2.参数:
name,redis的name
mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
# 如:
r.hmset('xx', {'k1':'v1', 'k2': 'v2'})
"""
conn.hmset('userinfo1',{'name':'nana','age':18}) # 弃用了,还能用
conn.hset('userinfo2',mapping={'name':'彭于晏','age':18})
hget(name,key)
在name对应的hash中获取根据key获取value
res =conn.hget('userinfo','name')
print(res) # 娜娜
hmget(name, keys, *args)
"""
1.在name对应的hash中获取多个key的值
2.参数:
# name,reids对应的name
# keys,要获取key集合,如:['k1', 'k2', 'k3']
# *args,要获取的key,如:k1,k2,k3
如:
# r.mget('xx', ['k1', 'k2'])
# 或
# print r.hmget('xx', 'k1', 'k2')
"""
res = conn.hmget('userinfo',['name','age'])
res1 = conn.hmget('userinfo','name','age')
print(res)
print(res1)
hgetall(name)
"""
1.获取name对应hash的所有键值
print(re.hgetall('xxx').get(b'name'))
2.慎用,如果hash中key非常的,可能会撑爆内存
"""
res = conn.hgetall('userinfo')
print(res) # {'name': '娜娜', 'age': '18', 'gender': 'female'}
hlen(name)
获取name对应的hash中键值对的个数
res = conn.hlen('userinfo')
print(res) # 3
hkeys(name)
获取name对应的hash中所有的key的值
print(conn.hkeys('userinfo')) # ['name', 'age', 'gender']
hvals(name)
获取name对应的hash中所有的value的值
print(conn.hvals('userinfo')) # ['娜娜', '18', 'female']
hexists(name, key)
检查name对应的hash是否存在当前传入的key
res = conn.hexists('userinfo','name')
res1 = conn.hexists('userinfo','hobby')
print(res) # True
print(res1) # False
hdel(name,*keys)
将name对应的hash中指定key的键值对删除
conn.hdel('userinfo','name','age')
hincrby(name, key, amount=1)
"""
自增name对应的hash中的指定key的值,不存在则创建key=amount
参数:
name,redis中的name
key, hash对应的key
amount,自增数(整数)
"""
conn.hincrby('userinfo','height')
hincrbyfloat(name, key, amount=1.0)
"""
1.自增name对应的hash中的指定key的值,不存在则创建key=amount
2.参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(浮点数)
3.自增name对应的hash中的指定key的值,不存在则创建key=amount
"""
conn.hincrbyfloat('userinfo','height')
hscan(name, cursor=0, match=None, count=None)
"""
1.增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
2.参数:
name,redis的name
cursor,游标(基于游标分批取获取数据)
match,匹配指定key,默认None 表示所有的key
count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
3.如:
第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
...
直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
"""
for i in range(1000):
conn.hset('hash_test','egg_%s'%i,'鸡蛋%s号'%i)
res = conn.hgetall('hash_test')
print(res)
res1 = conn.hscan('hash_test',cursor=0,count=20) # 分批获取,获取多少个,约等于,它不单独用
print(res1)
print(res1[1])
hscan_iter(name, match=None, count=None)
"""
1.利用yield封装hscan创建生成器,实现分批去redis中获取数据
2.参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
3.如:
# for item in r.hscan_iter('xx'):
# print item
"""
res = conn.hscan_iter('hash_test',count=10) # 取出所有,每次拿10条,用完再取10条,直到取完,内部使用了hscan+生成器
print(res) # <generator object ScanCommands.hscan_iter at 0x103d73140>
for item in res:
print(item)