redis的key是字符串类型, 而value可以是字符串类型 (memcached仅支持这一种类型)、列表类型、散列类型、集合类型、有序集合类型等等.
# redis version: 7.4.2
# python version: 3.11
# redis-py version: 6.2.0
import redis
# 连接本地 Redis 服务,默认端口是 6379
client = redis.Redis(host='localhost', port=6379, decode_responses=True)
通用命令是指与具体数据结构无关的命令.
1. *匹配0-任意个字符
2. ?匹配单个字符
3. [abc]匹配方括号内的任意一个字符
# 获取test开头的所有key
client.keys("test*")
# 迭代数据库中的数据库键
# SCAN 命令是一个基于游标的迭代器,每次被调用之后,都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数,以此来延续之前的迭代过程。
client.scan(cusor=0, match="*", count=1, _type="HASH")
# 4个重要参数
cursor: 游标位置, 直接用上一次scan命令的返回值
match: 与keys命令的pattern一致
count: 建议redis一次返回的数量, 但redis并不一定按照count返回
_type: 非检索条件, 只按redis数据结构类型对查询结果做一次过滤
# 是否存在key1
client.exists("key1")
# 查看my_hash_key的类型, 比如为hash类型
client.type("my_hash_key")
# 返回key1的ttl, 单位是秒, 如果是永久, ttl为-1
client.ttl("key1")
# 返回key1的ttl, 单位是毫秒, 如果是永久, pttl为-1
client.pttl("key1")
# 将ttl设置为永久
client.persist('key1')
# 设置my_hash_key的过期时间为10s
client.expire("my_hash_key", 10)
client.pexpire("my_hash_key", 10000)
# expireat和pexpireat是设置绝对时间, 而expire和pexpire是设置相对时间
# 4个重要参数
NX: 当且仅当该key 没有 设置过期时间
XX: 当且仅当该key 有 设置过期时间
GT: 当且仅当新的过期时间 大于 该key当前的过期时间
LT: 当且仅当新的过期时间 小于 该key当前的过期时间
# 删除key1 key2, 支持同时删除多个
client.delete('key1', 'key2')
# set命令有很多参数:
1. key/value: 将key的值设置成value
client.set('my_name', 'enroute')
2. NX/XX: 当且仅当key不存在/存在时
client.set('my_name', 'enroute', nx=True)
client.set('my_name', 'enroute', xx=True)
3. EX/PX/EXAT/PXAT: 相对时间-单位秒/相对时间-单位毫秒/绝对时间-单位秒/绝对时间-单位毫秒
// 1s后过期
client.set('my_name', 'enroute', ex=1)
client.set('my_name', 'enroute', px=1)
client.set('my_name', 'enroute', exat=int(time.time()) + 1)
client.set('my_name', 'enroute', exat=int(time.time()*1000) + 1000)
4. GET: 返回旧value
client.set('my_name', 'new enroute', get=True)
5. KEEPTTL: 保留key的旧ttl, 如果key不存在, 则不设置ttl
client.set('my_name', 'enroute', keepttl=True)
SETNX & SETEX & GETSET & PSETEX 其实都对应着 SET 命令的选项, redis官方已经不建议使用, 而是使用 SET 命令结合相应的选项, 比如:
SETNX (deprecated)
As of Redis version 2.6.12, this command is regarded as deprecated.
It can be replaced by SET with the
NX
argument when migrating or writing new code.
client.get("key1")
# 同时set多个, 但是不支持指定额外参数
client.mset({"key1": "value1", "key2": "value2"})
# 同时get多个
client.mget("key1", "key2")
# 给key1的值value1追加字符串, 结果为: value1_suffix
client.append("key1", "_suffix")
# 若key1的值为value1, setrange会将值改为vxxxe1, 等价于replace
# offset=1 为偏移量
# xxx为替换的字符串
client.setrange("key1", 1, "xxx")
# 若key1的值为value1, getrange会返回al, 等价于切片
# start=1 end=2, [start, end]
client.getrange("key1", 1, 2)
# 获取key1的值字符串长度
client.strlen("key1")
# 获取key1的值字符串长度
client.strlen("key1")
redis本身并没有指出数字类型, 只是在进行数字的相关操作时, redis会将字符串转为数字 (如果字符串不是数字会抛出异常), 并进行数字运算.
# 给key1的值value1加1
# 如果value1不是数字会报错
# 如果key1不存在, 会设置其值为1
client.incr("key1")
# 给key1的值value1加888
# 如果value1不是数字会报错
# 如果key1不存在, 会设置其值为888
client.incrby("key1", 888)
# 给key1的值value1减1
# 如果value1不是数字会报错
# 如果key1不存在, 会设置其值为-1
client.decr("key1")
# 给key1的值value1减888
# 如果value1不是数字会报错
# 如果key1不存在, 会设置其值为-888
client.decrby("key1", 888)
# 将key1的第10 bit位设置为1
client.setbit("key1", 10, 1)
# 获取key1的第10 bit位, 默认值为0
client.getbit("key1", 10)
可以当数组、链表、堆栈、队列使用
# 列表尾部添加任意数量元素
# 注意顺序是["v4","v5"]
client.rpush("list_key", "v4", "v5")
# 当且仅当列表存在时,向列表尾部添加一个元素
client.rpushx("list_key", "v4")
# 获取list的元素个数
client.llen("list_key")
# 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。
# 也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推
# 获取全部元素
client.lrange("list_key", 0, -1)
# 按数组下标访问元素
client.lindex("list_key", 2)
# 按数组下标设置元素, 当list_key不存在或者下标超出数组长度, 都会报错
client.lset("list_key", 1, "v3")
# 裁剪,只保留[start,end]的元素
# 裁剪掉首位元素
client.ltrim("list_key", 1, -2)
# 删除3个值为v2的元素
client.lrem("list_key", count=-3, "v2")
# count参数
count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
count = 0 : 移除表中所有与 VALUE 相等的值。
# 在v1元素之前或之后插入v3元素
client.linsert("list_key", "BEFORE", "v1", "v3")
client.linsert("list_key", "AFTER", "v1", "v3")
# 列表头部添加任意数量元素
# 注意顺序是["v2","v1"]
client.lpush("list_key", "v1", "v2")
# 当且仅当列表存在时,向列表头部添加一个元素
client.lpushx("list_key2", "v3")
# 弹出列表头部的元素
client.lpop("list_key")
# 比lpop多个timeout参数,当列表有元素直接弹出头部元素
# 当列表没有元素时会等待(单位秒)直到列表有元素或超时
client.blpop("list_key", timeout=3)
# 弹出列表头部的元素
client.rpop("list_key")
# 比rpop多个timeout参数,当列表有元素直接弹出尾部元素
# 当列表没有元素时会等待(单位秒)直到列表有元素或超时
client.brpop("list_key", timeout=3)
# 设置my_hash_key的field1值为value1, 支持同时set多个field
# HMSET功能与HSET一致
client.hset("my_hash_key", "field1", "value1")
# 当my_hash_key的field2不存在, 设置其值为value2
client.hsetnx("my_hash_key", "field2", "value2")
# 获取my_hash_key的field1的值
client.hget("my_hash_key", "field1")
# 获取my_hash_key的所有field的值
client.hgetall("my_hash_key")
# 获取my_hash_key的field1和field2的值, 支持同时获取多个field
client.hmget("my_hash_key", "field1", "field2")
# 获取my_hash_key的所有field
client.hkeys("my_hash_key")
# 获取my_hash_key的所有field的值
client.hvals("my_hash_key")
# my_hash_key所包含field的数量
client.hlen("my_hash_key")
# my_hash_key的field1对应值的字符串长度
client.hstrlen("my_hash_key", "field1")
# my_hash_key的field1是否存在
client.hexists("my_hash_key", "field1")
# 删除my_hash_key的field1和field2, 支持同时删除多个
client.hdel("my_hash_key", "field1", "field2")
# 迭代my_hash_key中的field和value
client.hscan("my_hash_key", cursor=0, match="*", count=1, no_values=True)
# 4个重要参数
cursor: 类似scan命令
match: 类似scan命令
count: 类似scan命令
no_values: 只返回field, 而不返回value
# 添加两个member1和member2到my_set_key, 支持同时添加多个
client.sadd("my_set_key", "member1", "member2")
# 查看my_set_key的所有member数量
client.scard("my_set_key")
# 查看member1是否是my_set_key中的member
client.sismember("my_set_key", "member1")
# 查看my_set_key中的所有member
client.smembers("my_set_key")
# 迭代my_set_key中的member
client.sscan("my_set_key", cursor=0, match="*", count=1)
# 4个重要参数
cursor: 类似scan命令
match: 类似scan命令
count: 类似scan命令
# 删除my_set_key中的member1和member2, 支持同时删除多个
client.srem("my_set_key", "member1", "member2")
# 将member1从my_set_key1中删除, 并添加到my_set_key2
# 如果my_set_key1不包含member1, 则不执行任何操作
client.smove("my_set_key1", "my_set_key2", "member1")
# 从my_set_key中随机弹出2个元素 (弹出意味着获取并删除), 返回值不重复
client.spop("my_set_key", 2)
# 从my_set_key中随机获取2个元素, 返回值不重复
client.srandmember("my_set_key", 2)
# 差集
# 返回在my_set_key1但不在my_set_key2中的所有元素
# my_set_key1和my_set_key2中的元素不变
client.sdiff("my_set_key1", "my_set_key2")
# 将差集结果放到dest_set_key中
# my_set_key1和my_set_key2中的元素不变
client.sdiffstore("dest_set_key", "my_set_key1", "my_set_key2")
# 交集
# 返回同时在my_set_key1和my_set_key2中的所有元素
# my_set_key1和my_set_key2中的元素不变
client.sinter("my_set_key1", "my_set_key2")
# 将交集结果放到dest_set_key中
# my_set_key1和my_set_key2中的元素不变
client.sinterstore("dest_set_key", "my_set_key1", "my_set_key2")
# 并集
# 返回在my_set_key1或者在my_set_key2中的所有元素
# my_set_key1和my_set_key2中的元素不变
client.sunion("my_set_key1", "my_set_key2")
# 将并集结果放到dest_set_key中
# my_set_key1和my_set_key2中的元素不变
client.sunionstore("dest_set_key", "my_set_key1", "my_set_key2")
有序集合 zset 和集合 set 一样不允许重复的成员, 不同的是 zset 每个成员都会关联一个 double 类型的分数, zset 的成员是唯一的, 但成员的分数可以重复。
有序集合 zset 的有序体现在:
1. 排序规则: 成员按分数进行排序。分数小的成员排在前面,分数大的成员排在后面。
2. 相同分数的成员顺序: 如果两个成员的分数相同,会按照成员的字典序进行排序。
# 为my_zset_key添加两个member, 分数分别为1.5和2
# 此命令也可更新已有member的score
client.zadd("my_zset_key", {"member1": 1.5, "member2": 2})
# 重要参数
NX: 当且仅当member不存在时才添加
XX: 当且仅当member存在时才更改score
GT/LT: 当且仅当新score 大于/小于 当前score才更新, 不影响添加操作
# 为my_zset_key的member1分数添加888
client.zincrby("my_zset_key", 888, "member1")
# 获取my_zset_key的member1分数
client.zscore("my_zset_key", "member1")
# 获取my_zset_key的member数量
client.zcard("my_zset_key")
# 迭代my_zset_key中的member
client.zscan("my_zset_key", cursor=0, match="*", count=1)
# 4个重要参数
cursor: 类似scan命令
match: 类似scan命令
count: 类似scan命令
# 按照下标获取my_zset_key的member, withscores=True表示同时获取member的score
client.zrange("my_zset_key", 0, -1)
client.zrange("my_zset_key", 0, -1, withscores=True)
# 同上, 只是顺序为按照score倒序
client.zrevrange("my_zset_key", 0, -1, withscores=True)
前提条件: 所有member都是相同的score, 才能保证字典序有意义
# 仅当所有member的score全部一样时, bylex才有意义
# 按字典序正序获取my_zset_key的member
client.zrangebylex("my_zset_key", min="(member1", max="+", start=1, num=2)
# 按字典序倒序获取my_zset_key的member
client.zrevrangebylex("my_zset_key", min="(member1", max="+", start=1, num=2)
# 4个重要参数
min: - 表示最小, (表示不包括边界, [表示包括边界
max: + 表示最大, (表示不包括边界, [表示包括边界
start: 表示offset
num: 表示pagesize
# 按照score正序获取my_zset_key的member
client.zrangebyscore("my_zset_key", min=1.0, max=3.5, start=0, num=10, withscores=True)
# 按照score倒序获取my_zset_key的member
client.zrevrangebyscore("my_zset_key", min=1.0, max=3.5, start=0, num=10, withscores=True)
# 5个重要参数
min: score下限
max: score上限
start: 表示offset
num: 表示pagesize
withscores: 表示是否返回score
# 获取my_zset_key的分数在[min, max]的成员数
client.zcount("my_zset_key", min=1, max=1.5)
# 获取my_zset_key的成员字典序在[min, max]的成员数
client.zlexcount("my_zset_key", min="(member1", max="+")
# 获取my_zset_key的成员member1的下标, withscore=True表示同时返回分数
client.zrank("my_zset_key", "member1", withscore=True)
# 获取my_zset_key的成员member1的倒序下标, withscore=True表示同时返回分数
client.zrevrank("my_zset_key", "member1", withscore=True)
ZREMRANGEBYLEX & ZREMRANGEBYRANK & ZREMRANGEBYSCORE
# 删除my_zset_key的成员member1 member2, 支持同时删除多个
client.zrem("my_zset_key", "member1", "member2")
# ZREMRANGEBYLEX & ZREMRANGEBYRANK & ZREMRANGEBYSCORE 按照选定范围批量删除
# 参考 ZRANGEBYLEX & ZRANGE & ZRANGEBYSCORE