-
set 设置值
R: set name lin
P: redis.set('name', 'lin')
set选项(原子操做)
nx(设置默认值)
R: set name lin nx
P: redis.set('name', 'lin', nx=True)
注: nx 表明key不存在才会将值设置成功, 相似python dict的 setdefault,即给key设置默认值
xx(更新值)
R: set name Tom xx
P: redis.set('name', 'lin', xx=True)
注: xx 表明key存在才会将值更新成功。 若是key不存在, 则更新失败。
-
get 获取值
R: get name
P: redis.get('name')
注:经过py redis客户端的 get取出的都是 字节二进制类型, 因此须要手动转为对应类型
前面提到的 incr decr 等, 操做返回结果直接就是 int, 而非 字节类型
-
mset 批量设置
R: mset name lin age 18
p: redis.mset( {'name': 'lin', 'age': 18} )
-
mget 批量获取
R: mget name age
p: redis.mget('name', 'age') # 返回值为 字节类型的 列表
-
getset 设置新值并返回旧值
R: getset name zhang
P: print( redis.getset('name', 'zhang') )
-
append 字符串追加拼接
R: append name abc
P: redis.append('name', 'abc')
-
strlen 获取字符串长度
R: strlen name
P: print( redis.strlen('name') )
注: 与编程语言的广泛API不一样的是, strlen返回的字符串 长度是 字符对应编码的长度。。。。
中文 utf-8 占 3个字节
-
getrange 字符串切片 (从0开始,前闭后闭)
R: getrange name 1 2
P: redis.getrange('name', 1, 2)
-
setrange 字符串按索引赋值(覆盖)
R: setrange name 0 abc # 把第0个位置开始, 逐个覆盖赋值为 abc, 多余的不变
P: redis.setrange('name', 0, 'abc')
-
del 删除键值
R: del k1 k2
P: redis.delete(k1, k2)
-
hset 设置 1条文档,1个属性-值
R: hset user name lin
P: redis.hset('user', 'name', 'lin')
-
hget 获取 1条文档,1个属性
R: hget user name
P: print(redis.hget('user', 'name'))
-
hmset 设置 1条文档, 多个属性-值
R: hmset user name lin age 18
P: redis.hmset('user', {'user': 'lin', 'age': 18})
-
hmget 获取 1条文档, 多个属性-值
R: hmget user name age
P: print(redis.hmget('user', 'name', 'age'))
-
hkeys 获取全部 key
R: hkeys user
P: print(redis.hkeys('user'))
-
hvals 获取全部 values
R: hvals user
P: print(redis.hvals('user'))
-
hgetall 获取 一条文档,全部属性值(慎用,见下一条API)
R: hgetall user # 返回为列表, 偶数索引为key,奇数索引为vaLue(从0开始)
P: print(redis.hgetall('user')) # 返回为 dict格式
注: hgetall 会将全部key-value取出来,因此数据量庞大可能会形成性能影响。
大批量数据在python是怎么处理来着???????
没错,就是迭代器,固然python的redis模块已为咱们封装好一个API,hscan_iter, 见一条API
-
hscan (hash迭代,大致上可代替 hgetall使用)
R: hscan user 0 match * count 200 # 按游标,按数量取
# 0表明游标从头开始
# match是关键字
# * 是key的通配符
# count 是一次接待的条数
P: result_iter = redis.hscan_iter('user', match= 'na*', count=2)
# python的 cursor参数没有,是由于源码中被固定设置为 0了, 其余参数解释同上
# 返回结果为可迭代对象,可遍历取出。
-
hexists 检测是否存在某key
R: hexists user name1 # 存在返回 1,不存在返回 0
P: print(redis.hexists('user', 'name')) # 存在返回True
-
hlen 统计获取一个文档,全部属性的 总数
R: hlen user
P: print(redis.hlen('user'))
-
hdel 删除指定字段
R: hdel key field
P: redis.hdel('key', 'field')
-
lpush (左压栈)
R: lpush list1 1 2 3
P: redis.lpush('list1', 1,2,3)
rpush (右压栈,同左压栈,略)
-
lpop (左弹栈)
R: lpop list2
P: print(redis.lpop('list2'))
rpop (右弹栈,同左弹栈,略)
-
blpop (左阻塞弹栈,列表为空时,就阻塞了)
R: blpop list2 1000 # 1000为过时时间为1000秒,1000秒后自动解除阻塞,有值加入也会解除阻塞
P: redis.blpop('list2', timeout=1000)
brpop (右阻塞弹栈,同左阻塞弹栈,略)
-
linsert ( 在指定 值 的 先后 插入值)
R: linsert list2 before Tom jerry # 在Tom前插入 jerry, before表明以前
P: redis.linsert('list2', 'after', 'b', 'Tom') # 在b的后面插入Tom, after表明以后
-
lset (按索引赋值, 注意索引不要越界)
R:lset list2 4 zhang
P: redis.lset('list2', 4, 'zhang')
-
lindex (按索引取值, 索引可正可负)
R: lindex list2 -3
P: print(redis.lindex('list2', 3))
-
llen (获取列表元素个数)
R: llen list2
P: print(redis.llen('list2'))
-
ltrim (注意:在原数据上切片,不返回值。)
R: ltrim list2 3 10 # 保留 索引 3-10 的列表数据,其余都删除
P: print(redis.ltrim('list2', 2, -1)) # 索引前闭后闭,可正可负
-
lrem (删除指定值)
R: lrem list2 0 Tom
# 0 这个位置的参数表明删除值的个数
# 0 表明所有删除, 删除所有Tom值
# 正数表明 从左到右 删除n个。 eg: lrem list2 5 Tom 即为 从左到右 删除5个Tom值
# 负数表明 从右到左 删除n个。 eg: lrem list2 -5 Tom 即为 从右到左 删除5个Tom值
P: print(redis.lrem('list2', -5, 1)) # 解释同上
-
lrange(遍历,正负索引均可,前闭后闭)
R: lrange list1 0 -1
P: print(redis.lrange('list2', 0, -1))
-
sadd (插入元素)
R: sadd set1 1 2 3
P: redis.sadd('set1', *[1,2,3])
-
srem (删除指定值的元素)
R: srem set1 Tom
P: redis.srem('set1', 'Tom')
-
scard (获取集合中元素个数)
R: scard set1
P: redis.scard('set1')
-
sismember (判断某元素是否在集合)
R: sismember set1 Tom
P: redis.sismember('set1', 'Tom')
-
srandmember (随机取出集合指定个数元素)
“”“相似py的 random.choices,注意有s”“
R: srandmember set1 2 # 从集合随机中取出2个元素
P: redis.srandmember('set1', 2)
-
smembers (取出集合中全部元素)
R: smembers set1
P: redis.smembers('set1')
注: 同 hgetall, 若是一次性取出,可能会出问题,因此须要迭代获取,见下 sscan
-
sscan (游标/迭代取出集合全部元素)
R: sscan set1 0 match * count 200
P: result_iter = redis.sscan_iter('set1', match='*', count=200) # 遍历迭代
-
sdiff (差集)
R: sdiff sset1 sset2
P: print(redis.sdiff('sset1', 'sset2'))
-
sinter(交集)
R: sinter sset1 sset2
P: print(redis.sinter('sset1', 'sset2'))
-
sunion (并集)
R: sunion sset1 sset2
P: print(redis.sunion('sset1', 'sset2'))
-
zadd (有序插入)
R: zadd zset 100 Tom 90 Jerry # 100是权重,Tom是数据值, 注意redis-cli 权重在前,值在后
P: redis.zadd('zset', {'Tom': 100, 'Jerry': 90}) # 注意,py语法,权重做为字典的value
注特别注意:
zadd的默认机制是同值,不一样权重时,会更新值的权重
eg: 上面再插入一条 Tom, 不过此次的权重是 50 ( zadd zset 50 Tom),则Tom的权重会更新为50
这时就延申出2个参数,(应该还记得前面讲的 set的 nx 和 xx参数吧,没错 zadd也有)
nx: (不存在才更新(添加), 存在则更新(添加) 失败)
R: zadd zset nx 1000 Tom
P: redis.zadd('zset',{'Tom': 1000}, nx=True)
注:
若是Tom这个值以前存在,则这个1000就不会被更新了
若不存在,则就会新建立,并把这个1000设置成功
nx:(存在才更新(添加), 不存在则更新(添加) 失败)
R: zadd zset xx 1000 Tom
P:redis.zadd('zset',{'Tom': 1000}, xx=True)
注:
若是Tom这个值以前存在,则1000才会更新成功
若是不存在,好比 {'张三':500}, 张三原本就不存在,用了xx, 他不会被添加进来,更何谈更新
-
zrange (遍历)
R: zrange zset 0 -1
P: print(redis.zrange('zset', 0, -1)) # 返回值为列表
withscores 参数(把权重也带出来返回):
R: zrange zset 0 -1 withscores # 注意, 返回时 奇数位 是值, 偶数位是权重
P: print(redis.zrange('zset', 0, -1, withscores=True)) # 返回列表嵌套元组,[(值,权重)]
-
zrevrange (逆序-降序,遍历)
这条API就是多了 "rev" 三个字母, reversed单词 熟悉把, python内置逆序高阶函数。。就是那个意思
操做同zrange,略
-
zrangebyscore (根据权重来遍历)
R: zrangebyscore zset 40 99 limit 1 3 # 查出权重在40-99以内的数据,并从第1条开始,返回3条
# 40-99都是闭区间, 要想变成开区间这样写便可 (40 (99
P: print(redis.zrangebyscore('zset', 40, 99, start=1, num=3))
-
zrevrangebyscore (根据权重来 逆序遍历)
操做同 zrangebyscore, 略
这API设计的,还不如,直接弄成一条命令,而后加一个逆序参数,吐槽!!!!
-
zrem (删除某值)
R: zrem zset Tom # 删除Tom这个值
P: print(redis.zrem('zset','Tom'))
-
zremrangebyscore (删除 权重 范围内的值)
R: zremrangebyscore zset 70 90 # 把权重在70-90分的全部数据删除
P: redis.zremrangebyscore('zset', 70, 90)
-
zremrangebyrank (删除 索引 范围内的值)
R: zremrangebyrank zset 0 -1 # 删除全部值 ( 0到-1的索引就表明全部值啦!)
P: redis.zremrangebyrank('zset', 0, -1) # redis的API风格真的。。。没办法python也无奈同名
-
zcard (获取有序集合的 全部 元素个数)
R: zcard zset
P: print(redis.zcard('zset'))
-
zcount (统计有序集合的 某权重范围的 元素个数)
R: zcount zset 10 69 # 一样默认闭区间, ( 可改成开区间
P: print(redis.zcount('zset',50, 69))
-
zrank (获取某元素的索引)
R: zrank zset Jerry # 不用猜,索引确定从0开始
P: print(redis.zrank('zset', 'Jerry'))
-
zrevrank (逆序 获取某元素的索引)
逆序获取索引,好比最后一个,索引就是0
具体操做,同 zrank, 略
-
zscore (获取某元素对应的权重)
R: zscore zset Jerry
P: print(redis.zscore('zset', 'Jerry'))
-
zscan (迭代方式和返回 全部元素及其权重)
"""
嗯?似曾相识燕归来?
前面说过的 scan hsacn sscan 还有接下来要说的 zscan 都是一个样子的,都是为了应对大数据来迭代处理
python版的redis给了咱们一个简化函数,那就是 _iter结尾的, eg: hscan_iter()
这种 _iter结尾的函数,不用咱们来传游标cursor参数, 为啥呢??
一. 由于python有生成器-迭代器机制阿!(固然 _iter等函数的源码就是用yield为咱们实现的)
二. cursor游标不易于管理
"""
R: zscan zset 0 match * count 5
P: zset_iter = redis.zscan_iter('zset', match='*', count=5) # 同理返回可迭代对象
注:还要说明一下:
match参数:
过滤查询数据(其实过滤完了,数据量小了也不必用scan了,此参数主要用在"hscan"之类的)
"所以match参数可不写", "match='*' 和 不传是一个效果的。"
count参数:
Py源码解释 ``count`` allows for hint the minimum number of returns
意思就是: 这个参数是一次迭代"最少"取5个",但无论怎么说,最终仍是会取出所有数据!!
-
zpopmax (弹出最大优先级数据对,redis5.+新增)
R: zpopmax zset1 2 # 2表明弹出最大的2对key:score,不写,默认只弹一对key:score
P: data = redis.zpopmax(zset1, count=None) # 原理同上
zpopmax可等价于下面两条命令的加起来的效果:
data = redis.zrange(zset1, -1, -1)
zrem(zset1, data)
注:不管count指定几个或不指定,py返回值为 [(key, score)] 列表嵌元组这种格式。
-
zpopmin (弹出最小优先级数据对,redis5.+新增)
用法同zpopmax
zpopmax可等价于下面两条命令的加起来的效果:
data = redis.zrange(zset1, 0, 0) # 就这里变了,默认升序,故最小值须要从第0条开始弹
zrem(zset1, data)
注:
zpopmax 和 zpopmin 这两个方法是 redis5.+才有的。
前面也说了这种方法 = zrange + zrem
很明显,由原来的多行操做。变成了原子操做。
我想,redis新增这两条命令,应该正是解决资源竞争的这一问题!!!!!!
-
生成RDB文件 (三种方法)
"""RDB机制就是 触发生成RDB文件,将Redis数据以二进制形式写入其中, 触发方式有以下三种"""
RDB基本配置:
vi /etc/redis/redis.conf
dbfilename dump.rdb # 配置RDB文件名
dir /var/lib/redis # 配置RDB文件存放目录 (ll 命令查看 dump.rdb是否为最新时间)
appendonly no # 若为yes, 会优先按照aof文件来恢复,或不恢复
上述配置,可在下面三种方法实现的时候,自动触发生成RDB文件。并在redis启动时恢复RDB文件
-
触发方式1:save (阻塞)
R: save
P: redis.save()
-
触发方式2:bgsave (开fork进程,异步,非阻塞)
R: bgsave
P: redis.bgsave()
-
触发方式3:自动动态生成RDB文件(配置文件)
在上面RDB基本配置基础上,追加以下配置
vi /etc/redis/redis.conf
save 100 10 # 100秒钟改变10条数据就会,自动生成RDB文件
-
RDB缺点
大数据耗时,RDB文件写入影响IO性能。宕机数据不可控
-
生成AOF文件(三种方法)
"""AOF机制就是 每执行一条命令,都会记录到缓冲区,在根据某种策略刷新到AOF文件中,策略有以下三种"""
AOF基本配置:
vi /etc/redis/redis.conf
appendonly yes # 开关,先要打开
appendfilename "appendonly.aof" # AOF文件名
dir /var/lib/redis # AOF文件目录(和RDB是同样的)
-
刷新策略1:always
always 即缓冲区有一条命令,就会刷新追加到AOF文件中 (安全可靠,耗IO)
-
刷新策略2:everysec (默认)
everysec 即每过1秒 就会把缓冲区的命令 刷新追加到AOF文件中
若是就在这一秒钟宕机,那么数据就丢失了。。。(1秒不可控)
-
刷新策略3:no
no 即 何时刷新,全听操做系统本身的 (彻底不可控)
AOF重写机制 (两种方法,异步)
-
重写清洁过程:
如上可知,愈来愈多的命令会追加到AOF中,其中可能会有一些相似
1、键值覆盖:
set name tom
set name jerry
2、超时时间过时
3、多条插入(可用一条命令代替)
如上无用命令,会让AOF文件变得繁杂。
可经过 AOF重写策略优化来达到化简,提升恢复速度等。
-
重写原理(查找资料 + 我的理解):
1、 开fork子进程 新弄一份AOF文件,它的任务就是把当前redis中的数据从新按照上面的
”重写清洁过程“ 捋一遍,并记录到这个新AOF文件中
2、 此时主进程能够正常接受用户的请求及修改,(这时可能子进程AOF,和数据库内容不一致,往下看)
3、 其实---第一条开fork的时候,顺便也开了一分内存空间A(名为重写缓冲区) 用来平行记录 用户新请求的命令
4、 当子进程AOF重写完过后, 会把上面 空间A中 中的数据命令追加到 AOF中(相似断点复制)
5、 新AOF替代 旧的AOF
打个比方(针对于 2、3、四):
就是,你给我一个任务,我正作着,你又给我不少任务,我固然忙不过来
那这样,你先拿个清单记录下来,一会等我忙完了,我们对接一下就行了)
-
重写方式1:bgrewriteaof
R: bgrewriteaof
P: redis.bgrewriteaof()
-
重写方式2:配置文件实现自动重写
在上面AOF基本配置的基础上,追加以下配置
vi /etc/redis/redis.conf
appendfsync everysec # 就是上面说的三种策略,选一种 always no
auto-aof-rewrite-min-size 64mb # 当AOF文件超过64mb就会自动重写
auto-aof-rewrite-percentage 100 # 100为增加率, 每一次的限制大小是以前的100%,也就是二倍
no-appendfsync-on-rewrite yes # yes 就是不把 “重写缓冲区” 的内容 刷新到 磁盘
注意这个参数:
这就是针对上面 ’重写原理‘ 中的第三条 中的 内存空间A(重写缓冲区)
若是这个 重写缓冲区 不刷新持久化到磁盘中, 要是宕机了,那么这个缓冲区的数据就会丢失。
丢失多少呢? 据悉(linux中 最多最多 会丢失 30秒的数据)
若是你将其 设置为 no,那么 重写缓冲区 就会像 前面讲的 原始AOF同样地 刷新持久化到硬盘中。
可是你想一想, 若是 重写缓冲区 和 原始AOF 都作持久化刷新
那么 它们就会 竞争 IO,性能一定大打折扣,特殊状况下,还可能 堵塞。
so, 要性能(设为yes), 要数据完整安全(设为no), 本身选....