Redis数据类型详解
Redis键/值介绍
Redis key值是二进制安全的,这意味着可以用任何二进制序列作为key值,从形如“foo”的简单字符串到一个JPG文件的内容都可以。空字符串也是有效key值。
key规则:
- 太长的键值不是个好主意,例如1024字节的键值就不是个好主意,不仅因为消耗内存,而且在数据中查找这类键值的计算成本很高。
- 太短的键值通常也不是好主意,如果你要用“u:1000:pwd”来代替
- 最好坚持一种模式。例如:"object-type:id:field"就是个不错的注意,像这样“user:1000:password”。或者一个键值对的字段名中加上一个点,就想这样“comment:1234:reply.to”。
数据类型:
String字符串类型
List列表数据类型
集合(Sets)类型
有序集合(Sorted Sets)类型
Hash类型
1.String字符串类型
这是Redis最简单的数据类型之一。如果只使用这种数据类型,那么redis就是一个持久化的memcached服务器当然redis对string类型的功能比memcached还是多很多的
常规的String字符串类型(key value):
127.0.0.1:6379> set wk >.>haoshuai #存入数据 key为wk 数据为>.>haoshuai OK 127.0.0.1:6379> get wk #查数据,get+key值查看 ">.>haoshuai"
value值可以是任何类型的字符串(包括二进制数据),例如你可以在一个键下保存一个jpg图片。但值的长度不能超过1GB
String类型也可以用来存储数字,并支持对数字的加减操作:
set id 1 #设置键为id 值为1 incr id #自增1 id变为2 incrby id 5 #自增指定数值5 id变为7 decr id #自减1 id变为6 decrby id5 #自减指定数值5 id变为1
为key设置新值并且返回原值
127.0.0.1:6379> set user01 zhangsan #设置新key-value OK 127.0.0.1:6379> get user01 "zhangsan" 127.0.0.1:6379> getset user01 wangwu #设置新数据并返回旧数据 "zhangsan" 127.0.0.1:6379> getset user01 liliu #设置新数据并返回旧数据 "wangwu" 127.0.0.1:6379> getset user01 gongli #设置新数据并返回旧数据 "liliu" 127.0.0.1:6379> get user01 "gongli"
String类型还支持批量读写操作
127.0.0.1:6379> mset name zhangsan age 44 OK 127.0.0.1:6379> mget name age 1) "zhangsan" 2) "44"
string类型还支持对其部分的修改和获取操作
127.0.0.1:6379> set images flower 127.0.0.1:6379> append images .jpg #追加字符串 127.0.0.1:6379> get images "flower.jpg"
2.List列表类型
列表list的用途:
list可被用来实现聊天系统。还可以作为不同进程间传递消息的队列。关键是,你可以每次都以原先添加的顺序访问数据。这不需要任何SQLORDER操作,将会非常快,也会很容易扩展到百万级别的规模。
在评级系统中,比如社会化新闻网站reddit.com,你可以把每个新提交的链接添加到一个list,用LRANGE可简单的对结果分页。
在博客引擎实现中,你可为每篇日志设置一个list,在该list中推入进博客评论,等等
向Redis list压入ID而不是实际的数据
127.0.0.1:6379> lpush students "zhangsan" #将元素“zhangsan”放在students列表的最左边 127.0.0.1:6379> lpush students "wangwu" #将元素“wangwu”插入列表的最左边 127.0.0.1:6379> lpush students "liliu" #将元素“liliu”插入列表的最左边 lrange students 0 2 #查看序列是0到2的元素 1) "liliu" 2) "wangwu" 3) "zhangsan" rpush students "wangyue" #将元素wangyue插入列表的最右边 lrange students 0 3 #查看序列是0到3的元素 1) "liliu" 2) "wangwu" 3) "zhangsan" 4) "wangyue" llen students #查看列表元素的个数 lpop students #移除最左边的元素值 rpop students #移除最右边的元素值 127.0.0.1:6379> rpush students zhangsan 127.0.0.1:6379> rpush students zhangsan 127.0.0.1:6379> lrange students 0 3 1) "wangwu" 2) "zhangsan" 3) "zhangsan" 4) "zhangsan" 127.0.0.1:6379> lrem students 2 "zhangsan" #删除列表里是“zhangsan”的元素,删除两次(从左向右删) 127.0.0.1:6379> lrange students 0 3 1) "wangwu" 2) "zhangsan" 127.0.0.1:6379> lrem students 1 "zhangsan" #删除列表里的元素zhangsan一次 127.0.0.1:6379> lrem students 0 "zhangsan" #清空列表所有的zhangsan元素
127.0.0.1:6379> lpush students a b c d #左插入元素abcd 127.0.0.1:6379> lrange students 0 4 1) "d" 2) "c" 3) "b" 4) "a" 127.0.0.1:6379> linsert students before b xxxx #在元素b的前边插入元素xxxx 127.0.0.1:6379> lrange students 0 9 1) "d" 2) "c" 3) "xxxx" 4) "b" 5) "a" 127.0.0.1:6379> linsert students after b xxxx #在元素b的后边插入元素xxxx 127.0.0.1:6379> lrange students 0 9 1) "d" 2) "c" 3) "xxxx" 4) "b" 5) "xxxx" 6) "a"
3.集合(Sets)类型
Redis集合是未排序的集合,其元素是二进制安全的字符串。SADD命令可以向集合添加一个新元素。和sets相关的操作也有许多,比如检测某个元素是否存在,以及实现交集,并集,差集等等。
edis能够将一系列不重复的值存储成一个集合
127.0.0.1:6379> sadd users laoda #向集合users里添加一个元素“laoda” 127.0.0.1:6379> sadd users laoer laosan #向结合users里添加两个元素laoer,laosan 127.0.0.1:6379> smembers users #查看集合里的所有元素 1) "laosan" #可以看到集合里的元素是无序的 2) "laoda" 3) "laoer" #我们向集合中添加了三个元素,并让Redis返回所有元素。现在让我们看一下某个元素是否存在于集合中 127.0.0.1:6379> sismember users laoda #查看元素laoda是否存在于集合users中 (integer) 1 #存在 127.0.0.1:6379> sismember users laoer #查看元素laoer是否存在于集合users中 (integer) 1 #存在 127.0.0.1:6379> sismember users laosan #查看元素laosan是否存在于集合users中 (integer) 1 #存在 127.0.0.1:6379> sismember users laosi #查看元素laosi是否存在于集合users中 (integer) 0 #不存在
“laoda”是这个集合的成员,而“laosi”不是。集合特别适合表现对象之间的关系。例如用Redis集合可以很容易实现标签功能。
下面是一个简单的方案:对每个想加标签的对象,用一个标签ID集合与之关联,并且对每个已有的标签,一组对象ID与之关联。
例如,假设我们的新闻ID1000被加了三个标签tag1,2,5和77,就可以设置下面两个集合:
sadd news:1000:tags 1 sadd news:1000:tags 2 sadd news:1000:tags 5 sadd news:1000:tags 77 sadd tag:1:objects 1000 sadd tag:2:objects 1000 sadd tag:5:objects 1000 sadd tag:27:objects 1000 #要获取一个对象的所有标签,我们只需要: #获取ID号为1000的所有新闻的题目 smembers news:1000:tags #获取集合为news:1000:tags的所有元素 1) "1" #新闻标题 2) "2" #新闻标题 3) "5" #新闻标题 4) "77" #新闻标题 #查询某个标签的具体内容,我们只需要: #获取某个新闻标题的具体内容 smembers tag:5:objects #获取集合为tag:5:objects的所有元素 1) "1000" #新闻内容
而有些看上去并不简单的操作仍然能使用相应的Redis命令轻松实现。例如我们也许想获得一份同时拥有标签1,2,10和27的对象列表。则可以用SINTER命令来做,他可以在不同集合之间取出交集。因此为达目的我们只需:
sadd tag:1:objects 500 #向集合tag:1:objects里添加元素“500” smembers tag:1:objects #查看集合tag:1:objects里的所有元素 1) "500" 2) "1000" smembers tag:2:objects #查看集合tag:2:objects里的所有元素 1) "1000" sinter tag:1:objects tag:2:objects tag:5:objects tag:27:objects #求集合tag:1:objects ...tag:27:objects里的所有元素的交集 1) "1000"
4 有序集合(Sorted Sets)类型
Sorted Sets和Sets结构相似,不同的是存在Sorted Sets中的数据会有一个score属性,并会在写入时就按这个score拍好序。
#向一个有序集合里添加元素 127.0.0.1:6379> ZADD days 0 mon #days是有序集合名,0是序号,mon是值 (integer) 1 127.0.0.1:6379> ZADD days 1 tue (integer) 1 127.0.0.1:6379> ZADD days 2 web (integer) 1 127.0.0.1:6379> ZADD days 3 thu (integer) 1 127.0.0.1:6379> ZADD days 4 fri (integer) 1 127.0.0.1:6379> ZADD days 5 sat (integer) 1 127.0.0.1:6379> ZADD days 6 sun (integer) 1 127.0.0.1:6379> zrange days 0 6 #查看集合索引0到6的元素 1) "mon" 2) "tue" 3) "web" 4) "thu" 5) "fri" 6) "sat" 7) "sun" #从上面我们可以看出,ZADD创建的集合是有序集合。 #查看有序集合days的具体值的排序 127.0.0.1:6379> zscore days mon "0" 127.0.0.1:6379> zscore days web "2" 127.0.0.1:6379> zscore days fri "4" root@redis-master ~]# redis-cli -a yunjisuan 127.0.0.1:6379> zscore days mon "0" 127.0.0.1:6379> zscore days web "2" 127.0.0.1:6379> zscore days fri "4" 127.0.0.1:6379> zcount days 3 6 (integer) 4 127.0.0.1:6379> ZRANGEBYSCORE days 3 6 1) "thu" 2) "fri" 3) "sat" 4) "sun"
- 集合是使用频率很高的数据类型,但是...对许多问题来说他们也有点太不讲顺序了;因此Redis1.2引入了有序集合。它和集合非常相似,也是二进制安全的字符串集合,但是这次带有关联的score,以及一个类似LRANGE的操作可以返回有序元素,此操作只能作用于有序集合,它就是,ZRANGE命令。
- 基本上有序集合从某种程度上说是SQL世界的索引在Redis中的等价物。例如在上面提到的reddit.com例子中,并没有提到如何根据用户投票和时间因素将新闻组合生成首页。我们将看到有序集合如何解决这个问题,但最好先从更简单的事情开始,阐明这个高级数据类型是如何工作的。让我们添加几个黑客,并将他们的生日作为“score”。
127.0.0.1:6379> zadd hackers 1940 "1940-Alan Kay" (integer) 1 127.0.0.1:6379> zadd hackers 1953 "1953-Richard Stallman" (integer) 1 127.0.0.1:6379> zadd hackers 1965 "1965-Yukihiro Matsumoto" (integer) 1 127.0.0.1:6379> zadd hackers 1916 "1916-Claude Shannon" (integer) 1 127.0.0.1:6379> zadd hackers 1969 "1969-Linus Torvalds" (integer) 1 127.0.0.1:6379> zadd hackers 1912 "1912-Alan Turing" (integer) 1
对有序集合来说,按生日排序返回这些黑客易如反掌,因为他们已经是有序的。有序集合是通过一个dual-ported数据结构实现的,它包含一个精简的有序列表和一个hash table,因此添加一个元素的时间复杂度是O(log(N))。这还行,但当我们需要访问有序的元素时,Redis不必再做任何事情,它已经是有序的了:
127.0.0.1:6379> zadd hackers 1940 "1940-Alan Kay" (integer) 1 127.0.0.1:6379> zadd hackers 1953 "1953-Richard Stallman" (integer) 1 127.0.0.1:6379> zadd hackers 1965 "1965-Yukihiro Matsumoto" (integer) 1 127.0.0.1:6379> zadd hackers 1916 "1916-Claude Shannon" (integer) 1 127.0.0.1:6379> zadd hackers 1969 "1969-Linus Torvalds" (integer) 1 127.0.0.1:6379> zadd hackers 1912 "1912-Alan Turing" (integer) 1 #利用zrange进行排序查询 127.0.0.1:6379> zrange hackers 0 6 1) "1912-Alan Turing" 2) "1916-Claude Shannon" 3) "1940-Alan Kay" 4) "1953-Richard Stallman" 5) "1965-Yukihiro Matsumoto" 6) "1969-Linus Torvalds" #利用zrevrange进行反向查询 127.0.0.1:6379> zrevrange hackers 0 -1 1) "1969-Linus Torvalds" 2) "1965-Yukihiro Matsumoto" 3) "1953-Richard Stallman" 4) "1940-Alan Kay" 5) "1916-Claude Shannon" 6) "1912-Alan Turing"
5 Hash类型
Redis能够存储key对多个属性的数据(比如user1,uname user1.passwd)
#存储一个hash类型test,他的属性是name,属性数据是yunjisuan 127.0.0.1:6379> hset test name yunjisuan (integer) 1 #存储一个hash类型test,他的属性是age,属性数据是35 127.0.0.1:6379> hset test age 35 (integer) 1 #存储一个hash类型test,他的属性是sex,属性数据是non 127.0.0.1:6379> hset test sex nan (integer) 1 #查看hash类型test的所有属性的值 127.0.0.1:6379> hvals test 1) "yunjisuan" 2) "35" 3) "nan" #查看hash类型test的所有属性及属性所对应的值 127.0.0.1:6379> hgetall test 1) "name" 2) "yunjisuan" 3) "age" 4) "35" 5) "sex" 6) "nan"
开启redis的订阅功能
#开启redis的订阅功能 redis-cli 127.0.0.1:6379> subscribe yunjisuan #开启频道名:yunjisuan的订阅功能,可开启多个窗口进行订阅 #对频道进行内容推送 只要在推送端推送,订阅端就能看到 redis-cli 127.0.0.1:6379> publish yunjisuan 'welcome' #向频道yunjisuan推送welcome (integer) 2 #推送成功的人数 127.0.0.1:6379> publish yunjisuan '很高兴' (integer) 2 127.0.0.1:6379> publish yunjisuan 'welcome' (integer) 3