详解Redis五种数据类型(string,list,hash,set,zset)及其使用场景

2018-06-17 11:34:21 Python 阅读 (8950) 评论(0)

    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的这几种数据类型,灵活运用,可以帮助我们实现很多业务逻辑需求。

评论