88、Redis介绍和安装、redis普通连接和连接池、redis 字符串类型、redis hash类型

107 阅读10分钟

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)