001.redis总结

Redis介绍

博客地址:https://www.cnblogs.com/liuqingzheng/articles/9833534.html

1 非关系型数据库,纯内存操作,key-value存储,性能很高
2 缓存,计数器,验证码,geo地理位置信息,发布订阅,独立用户统计
3 5大数据类型:字符串,列表,hash,集合,有序集合
4 6.x之前是单线程,单进程,为什么这么快?  qps:每秒查询率:10w,真实6w
	-纯内存操作
    -使用了io多路复用的模型,epoll  (select,poll,epoll)
    -避免了线程间切换的浪费
5 redis安装
	-官方提供了 源码 c语言,编译安装
    -编译型语言,如果要执行,需要在不同平台编译成不同平台的可执行文件
    -在linux装,编译(gcc),编译成可执行文件,就可以运行
    -win:不支持win,5.x  3.x基础,一路下一步
    -监听的端口是:6379
    -win上自动做成服务,启动关闭服务
    -使用命令启动服务端
    	redis-server 配置文件
    -客户端连接:命令窗口
    	redis-cli
    -python代码连接
    -图形化客户端:很多
    	-redis-desktop-manager:一路下一步
         -连远端可以,
    	
# 补充        
6 QT:平台
	-使用c/C++语言在平台上开发----》图形化界面软件(GUI)
    -pyqt:在qt平台上使用python代码写图形化界面
    -Tkinter
    
    
7 django 2.0.7以后,如果还使用pymysql连mysql,源码不兼容,改源码
	-mysqlclient:什么都不用配,直接用,不需要改源码

1 Python操作Redis之普通连接和连接池


下载redis模块,pip install redis

#### redis之普通连接
import redis

# 拿到一个连接,通过连接操作数据
# conn = redis.Redis()
conn = redis.Redis(host='localhost', port=6379)
conn.set('name','lqz')
conn.close()



#### redis连接池

import redis
from pool import POOL
# 从池中获取连接
conn=redis.Redis(connection_pool=POOL)
# 设置age的值为24
conn.set('age',14)
conn.close()



# 创建池,池的大小是10,最多放10个连接
# 池需要做成单例,整个项目全局只有一个
# Python 的模块就是天然的单例模式
# 在pool.py中设置链接池大小
import redis
POOL = redis.ConnectionPool(max_connections=10)

2 Python操作Redis之字符串操作

import redis
conn = redis.Redis(host='localhost',port=6379)

set(name, value, ex=None, px=None, nx=False, xx=False)(重要)

ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有key不存在时,才会为key赋值value
xx,如果设置为True,则只有key存在时,才会为key赋值value

conn.set('hobby','篮球',ex=8) # 8秒后清空
conn.set('names','aaa',xx=True) # names存在则赋值为aaa
conn.set('names','aaa',nx=True) # names不存在则赋值aaa
print(conn.get('names'))

setnx(name,value)

conn.setnx('name','ddd') # key值存在则值不变
print(conn.get('name'))
conn.setnx('name1','ddd') # key值不存在,则给这个key赋值
print(conn.get('name1'))

setex(name, time, value)

conn.setex('age',18,5) # 设置age的值为5,18秒后清空

psetex(name, time_ms, value)

conn.psetex('xx',3000,'ss') #  字符串xx的值为'ss',以毫秒为过期时间

mset(*args, **kwargs) 批量设置(重要)

conn.mset({'name2':'egon','name3':'lyf'}) # 批量设置name2和name3

get(name) 获取字符串的值,值的类型是byte格式(重要)

print(conn.get('name2')) # 获取'name2'的值,byte格式

mget({‘k1’: ‘v1’, ‘k2’: ‘v2’}) 批量获取key值(重要)

res=conn.mget('name1','name2') # 可以放多个key值
res=conn.mget(['name1','name2']) # 也可以用列表放key值

getset(name, value) 获取原值并设置新值

res=conn.getset('name1','ppp') # 获取name1,并将name1设置成'pop'
print(res)

getrange(key, start, end) 获取字符串指定范围:[start,and]闭区间

res=conn.getrange('name1',0,5) # 获取字符串中索引0到5夫人字符串
print(res.decode('utf-8'))

setrange(name, offset, value)

修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
参数: offset,字符串的索引,字节(一个汉字三个字节)
value,要设置的值

conn.setrange('name1',10,'pppppp')
# 向索引10开始替换pppppp

setbit(name, offset, value)

参数:
    -name,redis的name
    -offset,位的索引(将值变换成二进制后再进行索引)
    -value,值只能是 10
 
注:如果在Redis中有一个对应: n1 = "foo",
        那么字符串foo的二进制表示为:01100110 01101111 01101111
    所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
        那么最终二进制则变成 01100111 01101111 01101111,即:"goo"

getbit(name, offset)

获取name对应的值的二进制表示中的某位的值 (0或1)

print(conn.getbit('name1',2)) # 获取索引2的值,值为0或1

bitcount(key, start=None, end=None)

获取name对应的值的二进制表示中 1 的个数
参数:
    - key,Redis的name
    - start,位起始位置
    - end,位结束位置

strlen(name) 获取字符串字节长度(重要)

返回name对应值的字节长度(一个汉字3个字节)

print(conn.strlen('name1')) 

incr(self, name, amount=1) 自增(重要)

- 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
 
- 参数:
    - name,Redis的name
    - amount,自增数(必须是整数)
 
- 注:同incrby

conn.incr('name1')  # 自增1

decr(self, name, amount=1) 自减

- 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
 
- 参数:
    - name,Redis的name
    - amount,自减数(整数)

incrbyfloat(self, name, amount=1.0)自增

- 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
 
- 参数:
    - name,Redis的name
    - amount,自增数(浮点型)
    
conn.incrbyfloat('name1',1.2)
print(res)

3 Python操作Redis之hash操作

import redis
conn = redis.Redis()

hset(name, key, value)(重要)

name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
参数: name,redis的name
key,name对应的hash中的key
value,name对应的hash中的value
注:hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)

conn.hset('hash1','name','lqz')
conn.hset('hash1', 'age', '19')

hget(name,key)(重要)

在name对应的hash中获取根据key获取value

print(conn.hget('hash1','age')) # 获取hash1中age对应的值

hmset(name, mapping) # 弃用了,但是还可以用(重要)

在name对应的hash中批量设置键值对
参数:
name,redis的name
mapping,字典,如:{‘k1’:‘v1’, ‘k2’: ‘v2’}

conn.hmset('user_1_info', {'name': 'lyf', 'age': 33,'hobby':'篮球'})
conn.hset('user_2_info', mapping={'name': 'lyf', 'age': 33,'hobby':'篮球'})

hmget(name, keys, *args)(重要)

在name对应的hash中获取多个key的值
参数:
name,reids对应的name
keys,要获取key集合,如:[‘k1’, ‘k2’, ‘k3’]
*args,要获取的key,如:k1,k2,k3

res=conn.hmget('user_2_info','age','hobby')
res = conn.hmget('user_2_info', ['age', 'hobby'])
print(res)

list_or_args使用

from redis.client import list_or_args

conn.hmget('user_2_info','age','hobby')
res = list_or_args('age', ['hobby', ])

res = conn.hmget('user_2_info', ['age', 'hobby'])
res = list_or_args(['age', 'hobby'],[])
print(res)

hgetall(name) 获取所有 ,慎用,生产环境中,尽量不要用

res=conn.hgetall('user_2_info')
print(res)

hlen(name)获取name对应的hash中键值对的个数(重要)

res=conn.hlen('user_2_info')
print(res)

hkeys(name)获取name对应的hash中所有的key的值

res=conn.hkeys('user_2_info')
print(res)

hvals(name)获取name对应的hash中所有的value的值

res=conn.hvals('user_2_info')
print(res)

hexists(name, key)检查name对应的hash是否存在当前传入的key(重要)

res=conn.hexists('user_2_info','name1')
print(res)

hdel(name,*keys)将name对应的hash中指定key的键值对删除

res=conn.hdel('user_2_info','name')
print(res)

hincrby(name, key, amount=1)(重要)

自增name对应的hash中的指定key的值,不存在则创建key=amount
参数:name,redis中的name
key, hash对应的key
amount,自增数(整数)

conn.hincrby('user_2_info','age')

hincrbyfloat(name, key, amount=1.0)

自增name对应的hash中的指定key的值,不存在则创建key=amount
参数:
    - name,redis中的name
    - key, hash对应的key
    - amount,自增数(浮点数)
自增name对应的hash中的指定key的值,不存在则创建key=amount

hscan(name, cursor=0, match=None, count=None)

增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
参数:
name,redis的name
cursor,游标(基于游标分批取获取数据)
match,匹配指定key,默认None 表示所有的key
count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数

# 由于无序,这个方法咱们一般不同,给hscan_iter,从hash中取出一部分值,会以count为基准,但不完全是count
res=conn.hscan('test_hash',count=11)
print(len(res[1]))

hscan_iter(name, match=None, count=None)(重要)

利用yield封装hscan创建生成器,实现分批去redis中获取数据
参数:
match,匹配指定key,默认None 表示所有的key
count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数

# hash 类型本身就无需
# for i in range(1000):
#     conn.hset('test_hash','%s_key'%i,'鸡蛋_%s'%i)
# res=conn.hgetall('test_hash')

# 取出所有数据,跟hgetall比,更节省内存
for key in conn.hscan_iter('test_hash',count=100):  # 生成器
    print(key)

4 Python操作Redis之列表操作

# redis 之列表操作
import redis
conn = redis.Redis()

lpush(name,values) # 从列表的左侧插入值(重要)

conn.lpush('names','lqz','egon')
conn.lpush('names','lyf','dlrb')
conn.lpush('names','pyy')
# 顺序:['pyy','dlrb','lyf','egon','lqz']

conn.rpush('names','mrzh')
# rpush(name, values) 表示从右向左操作

lpushx(name,value) # 只能key存在,才能放进去

在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
更多:rpushx(name, value) 表示从右向左操作

conn.lpushx('names','999')
conn.lpushx('names1','999') #不存在的放不进去

llen(name) name对应的list元素的个数(重要)

print(conn.llen('names'))

linsert(name, where, refvalue, value))

在name对应的列表的某一个值前或后插入一个新值
参数:name,redis的name
where,BEFORE或AFTER(小写也可以)
refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
value,要插入的数据

# where:before或者after,大小写都可以
conn.linsert('names','after','egon','fengjie')
conn.linsert('names','BEFORE','egon','rh')

r.lset(name, index, value) 位置从零开始

对name对应的list中的某一个索引位置重新赋值
参数:name,redis的name
index,list的索引位置
value,要设置的值

conn.lset('names',5,'l_egon')

r.lrem(name, num,value )(重要)

在name对应的list中删除指定的值
参数:name,redis的name
value,要删除的值
num, num=0,删除列表中所有的指定值;
num=2,从前到后,删除2个;
num=-2,从后向前,删除2个

conn.lrem('names',0,'lqz')  #把内部所有lqz都移除
conn.lrem('names',1,'lqz')  #从左往右移除一个符合
conn.lrem('names', -1, 'lqz')  # 从右往左移除一个符合

lpop(name)(重要)

在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
更多: rpop(name) 表示从右向左操作

conn.lpop('names')   # 从左侧弹出一个
conn.rpop('names')   # 从右侧弹出一个

lindex(name, index) 拿某个位置的值,从0开始(重要)

在name对应的列表中根据索引获取列表元素

res=conn.lindex('names',1)
print(res)

lrange(name, start, end)(重要)

在name对应的列表分片获取数据
参数:name,redis的name
start,索引的起始位置
end,索引结束位置

print(re.lrange('aa',0,re.llen('aa')))
res=conn.lrange('names',1,conn.llen('names'))  # 获取起始到结束位置的值,前闭后闭
print(res)

ltrim(name, start, end) 修剪

在name对应的列表中移除没有在start-end索引之间的值
参数:name,redis的name
start,索引的起始位置
end,索引结束位置(大于列表长度,则代表不移除任何)

res=conn.ltrim('names',2,4)  # 只保留2--4之间的,其他全删除

rpoplpush(src, dst) # 两个列表

从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
参数:src,要取数据的列表的name
dst,要添加数据的列表的name

conn.lpush('names1','xx','yy')
conn.rpoplpush('names','names1')

blpop(keys, timeout) 阻塞式弹出,有值可以弹,没有值就夯住,直到有值,

将多个列表排列,按照从左到右去pop对应列表的元素
参数:keys,redis的name的集合
timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
更多:
r.brpop(keys, timeout),从右向左获取数据
爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式

# 基于它可以做消息队列,如果是简单的消息队列,就可以使用redis的list类型
res=conn.blpop('names',4)  # 超时时间
print(res)

brpoplpush(src, dst, timeout=0)

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

# 一次性把list中值全取出来
res = conn.lrange('names', 0, conn.llen('names'))

自定义增量迭代取值(哪个地方用过生成器)

由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
1、获取name对应的所有列表
2、循环列表
但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:

import redis
conn=redis.Redis(host='127.0.0.1',port=6379)

# conn.lpush('test',*[1,2,3,4,45,5,6,7,7,8,43,5,6,768,89,9,65,4,23,54,6757,8,68])

def scan_list(name, count=2):
    index = 0
    while True:
        data_list = conn.lrange(name, index, count + index - 1)
        if not data_list:
            return
        index += count
        for item in data_list:
            yield item


for item in scan_list('test',2):
    print(item)

5 Redis其他操作(通用操作)

import redis

conn=redis.Redis()

delete(*names) 根据删除redis中的任意数据类型

conn.delete('test_hash')

exists(name)检测redis的name是否存在

res=conn.exists('names')
print(res)  # 1 表示存在  0表示不在

keys(pattern=’*’) 获取所有的key值,可以过滤

根据模型获取redis的name
更多:KEYS * 匹配数据库中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS h*llo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

res=conn.keys(pattern='n*')
res=conn.keys(pattern='nam?')
print(res)

expire(name ,time)为某个redis的某个name设置超时时间

conn.expire('names1',9)

rename(src, dst)对redis的name重命名

conn.rename('test','test1')

move(name, db))将redis的某个值移动到指定的db下

conn.move('hash1',5)

randomkey()随机获取一个redis的name(不删除)

res=conn.randomkey()
print(res)

type(name) 查看key的类型 5 大数据类型

res=conn.type('user_1_info')
res=conn.type('name1')
print(res)

6 管道(pipline)

# redis是非关系型数据库,不支持事务
# 管道,我们可以通过管道来模拟事务----》要么都成功,要么都失败:一个事务

import redis

conn = redis.Redis()

# 创建一个管道
pipe = conn.pipeline(transaction=True)
# 开启事务
pipe.multi()

#向管道中放入命令

#向管道中放入命令
pipe.decrby('egon_money',50)
# raise Exception('ssss')
pipe.incrby('lqz_money',50)

pipe.execute() #让管道中的命令执行

7 Django中使用redis

7.1 通用方案

pool.py

import redis

POOL = redis.ConnectionPool(max_connections=1000)

在使用的位置

from .pool import POOL
import redis
def test(request):
    conn = redis.Redis(connection_pool=POOL)
    res=conn.get('name')
    print(res)
    return HttpResponse('ok')

7.2 django方案,第三方模块

pip install django-redis

# 在配置文件中写
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "123",
        }
    }
}


# 使用的位置
from django_redis import get_redis_connection
def test(request):
    conn = get_redis_connection()  #从连接池中拿一个连接
    res=conn.get('name')
    print(res)
    return HttpResponse('ok')


# 一旦使用了它,后续的djagno缓存,都缓存到redis中
cache.set('name','xxx')
# django的缓存很高级,可以缓存python中所有的数据类型,包括对象---》把对象通过pickle序列化成二进制,存到redis的字符串中
    

作业

1 三大数据类型所有操作,实验一把,把笔记整理出来
2 redis其他操作,管道,django中集成,都写一下

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值