Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。下面演示代码为Python操作Redis。
一. String(字符串)
string是Redis最基本的数据类型,一个key对应一个value。
string类型理论上可以存储大部分编程语言(如PHP,Java,Python等)中涉及到的各种各样的数据结构(数组,对象,字符串,列表,字典,集合等),这些数据可以原封不动的存储到redis的string里,也可以转换为json或序列化后存储到redis里,图片也可以经过base64转码后存储。
string类型一个key最大可以存储512M的数据,不建议存储过大的数据。
from redis import StrictRedis redis = StrictRedis(host='localhost', port=6379, decode_responses=True) redis.set('username', '小明', ex=1) # 增 redis.delete('username') # 删 redis.set('username', '小明明') # 改 username = redis.get('username') # 查 print(username)
上面就是在redis里保存一个key为username,对应value为‘小明’的数据,ex参数为过期时间(单位是秒)。
如果有同名的key,会直接覆盖原来的value,保存为最新设置的value。
二. Hash(哈希)
hash是一个string类型的key和value的映射表。Redis在处理hash数据时,可以理解成在redis中维护了很多个hash(一个hash key对应一个表)表,在每个hash表中又可以像string 类型一样存储key-value数据,所以每个hash数据可以理解成是有两个key的。
redis.hset('article', 1, '第一页数据') redis.hset('article', 2, '第二页数据') res = redis.hget('article', 1) # 打印输出为 第一页数据 res = redis.hget('article', 2) # 打印输出为 第二页数据 print(res)
如上就是在redis新建一个article的hash表,然后在这个hash表中,分别存入key为1时的value('第一页数据'),key为2时的value('第二页数据')。
像一些商品缓存或文章缓存就可以存入hash,商品分类名或文章分类名作为hash key,对应每一页的页码作为hash表里的key,对应的商品/文章数据作为hash表里的value。redis hash还适合存储对象数据,如下:对象名做hash的key,各个对象属性和属性的值存到这个hash表里:
class User: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex user = User('小明', 18, '男') redis.hmset('user', {'name': user.name, 'age': user.age, 'sex': user.sex}) res = redis.hmget('user', ('name', 'age', 'sex')) print(res) # 打印输出为 ['小明', '18', '男']
此外,hash还有hdel,hlen,hgetall等其他方法。
三. list(列表)
redis list是链表结构,类似于数组(列表),是有序的,是双向的,可以在链表左右两边分别操作。由此list经常作为消息队列使用,按照插入顺序,逐个弹出,然后执行相应的操作,如下:
# 入队列 for i in range(10): redis.lpush('visitors', '我是第{}个访问用户'.format(i)) # 出队列 while True: res = redis.rpop('visitors') if res is None: print('over') break print(res)
消息队列的入队列和出队列可以放到两个程序(进程,线程等都可以),也可以一个程序入队列,使用Linux的contrab命令写一个定时脚本去取队列的信息,然后执行相应的操作,crontab命令可以参考crontab命令参考。
常用的list方法还有:
# rpush/rpushx 有序列表操作,从队列后插入元素, lpush/lpushx 和rpush/rpushx的区别是插入到队列的头部,同上,'x'含义是只对已存在的key进行操作 redis.rpush('test_list', 'bar1') # 返回一个列表的长度1 redis.lpush('test_list', 'bar0') # 返回一个列表的长度2 redis.rpushx('test_list', 'bar2') # 返回3,rpushx只对已存在的队列做添加,否则返回0 # llen返回当前列表长度 redis.llen('test_list') # 3 # lrange 返回队列中一个区间的元素 redis.lrange('test_list', 0, 1) # 返回数组包含第0个至第1个共2个元素 redis.lrange('test_list', 0, -1) # 返回第0个至倒数第一个,相当于返回所有元素,注意redis中很多时候会用到负数,下同 # lindex 返回指定顺序位置的list元素 redis.lindex('test_list', 1) # 返回'bar1' # lset 修改队列中指定位置的value redis.lset('test_list', 1, '123') # 修改位置1的元素,返回true # lrem 删除队列中左起指定数量的字符 redis.lrem('test_list', 1, '_') # 删除队列中左起(右起使用-1)1个字符'_'(若有)
四. Set 集合
redis set集合,就是一堆不重复值的无序的组合,关键词为不重复和无序。
redis.sadd('set1', 1) # 1 redis.sadd('set1', 2) # 1 redis.sadd('set1', 1) # 0 redis.sadd('set1', 2) # 0 redis.sadd('set1', 3) # 1
如上,就是集合的插入操作,1是插入成功,0是失败,redis set会自动检测该集合中是否已有该值。
集合的交并差:
其中注意sdiff求差集时,跟集合参数顺序有关,返回的是第一个集合没有而第二个集合有的元素,sdiffstore同理。
redis.sadd('test_set1', 1) redis.sadd('test_set1', 2) redis.sadd('test_set1', 3) redis.sadd('test_set1', 4) redis.sadd('test_set2', 1) redis.sadd('test_set2', 2) redis.sadd('test_set2', 5) redis.sadd('test_set2', 6) # 差集 print(redis.sdiff('test_set2', 'test_set1')) # {'5', '6'} redis.sdiffstore('set3', 'test_set2', 'test_set1') print(redis.smembers('set3')) # {'5', '6'} # 并集 print(redis.sinter('test_set1', 'test_set2')) # {'2', '1'} redis.sinterstore('set4', 'test_set1', 'test_set2') print(redis.smembers('set4')) # {'2', '1'} # 差集 print(redis.sunion('test_set1', 'test_set2')) # {'1', '2', '4', '6', '3', '5'} redis.sunionstore('set5', 'test_set1', 'test_set2') print(redis.smembers('set5')) # {'1', '2', '4', '6', '3', '5'}
此外集合还有 smembers , spop , scard, sismember, srem等其他方法。
由集合里的数据不重复的特性,可以实现很多业务逻辑,比如好友,我有一堆好友存在一个集合里,你有一堆好友存在集合里,由这两个集合就可以看出我们两个人之间共同的好友。
集合还可以做一些简单去重的功能需求,比如说,写爬虫时,可以把爬取的URL添加到集合里,根据返回结果,可知集合中有无此URL。
五. Zset 有序集合
zset也是集合,相较于set的无序,zset是有序集合,zset每个元素都有一个关联的double类型的分数(权重)用于内部排序。zset元素也是不重复的。
redis.zadd('users', 1, '小明') redis.zadd('users', 1, '小明') redis.zadd('users', 2.1, '小明') redis.zadd('users', 2, '小刚') redis.zadd('users', 5, '小红') redis.zadd('users', 9, '小二') redis.zadd('users', 3, '小小') res = redis.zrange('users', 0, -1) print(res) # 打印出的列表顺序是按照zset元素的score值从小到大组成的--》['小刚', '小明', '小小', '小红', '小二']
如上插入操作,第一个参数是zset的key,第二个参数是用于排序的数值score,第三个是value,当有重复的元素添加时,添加不成功,如果第二次添加时score值不一样,就更新这个score。
zset和set的差别是有序的,所以其他功能操作大致相同,还有zadd, zrem,zrange,zcard等等其他方法。
因为zset是有序集合,因此可以处理一些需要有排序功能的业务场景,比如排行榜和上面提到的消息队列也可用zset实现,还能在消息队列基础上加上权重,哪个“消息”放在前面,先被处理。
Redis的这几种数据类型,灵活运用,可以帮助我们实现很多业务逻辑需求。