一、 了解Redis
(一) Redis历史
2008年,意大利的一家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG,然而没过多久该公司的创始人 Salvatore Sanfilippo便对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身定做一个数据库,并于2009年开发完成,这个数据库就是Redis。 不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo将Redis开源发布,并开始和Redis的另一名主要的代码贡献者Pieter Noordhuis一起继续着Redis的开发,直到今天。
Salvatore Sanfilippo自己也没有想到,短短的几年时间,Redis就拥有了庞大的用户群体。Hacker News在2012年发布了一份数据库的使用情况调查,结果显示有近12%的公司在使用Redis。国内如新浪微博、街旁网、知乎网,国外如GitHub、Stack Overflow、Flickr等都是Redis的用户。
VMware公司从2010年开始赞助Redis的开发, Salvatore Sanfilippo和Pieter Noordhuis也分别在3月和5月加入VMware,全职开发Redis。
(二) 什么是Redis
1. 什么是NoSql?
为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方案,就是NoSql数据库。
NoSQL,泛指非关系型的数据库,NoSQL即Not-Only SQL,它可以作为关系型数据库的良好补充。但是它不能替代关系型数据库,而且它是存储在内存中,所以它的访问速度很快。
2. Nosql的数据库分类
类型 |
相关产品 |
典型应用 |
数据模型 |
优势 |
劣势 |
键值(Key-Value)存储数据库 |
Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB |
内容缓存,主要用于处理大量数据的高访问负载。 |
一系列键值对 |
快速查询 |
存储的数据缺少结构化 |
列存储数据库 |
Cassandra, HBase, Riak |
分布式的文件系统 |
以列簇式存储,将同一列数据存在文件系统中 |
查找速度快,可扩展性强,更容易进行分布式扩展 |
功能相对局限 |
文档型数据库 |
CouchDB、MongoDB |
Web应用(与Key-Value类似,Value是结构化的) |
一系列键值对 |
数据结构要求不严格 |
查询性能不高,而且缺乏统一的查询语法 |
图形(Graph)数据库 |
Neo4J、InfoGrid、Infinite Graph |
社交网络 |
图结构 |
利用图结构相关算法 |
需要对整个图做计算才能得出结果,不容易做分布式的集群方案。 |
3. 关于Redis
Redis是用C语言开发的一个开源的(BSD许可)、高性能的、基于键值对的缓存与存储系统,通过提供多种键值数据类型来适应不同场景下的缓存与存储需求。同时Redis的诸多高层级功能使其可以胜任消息队列、任务队列等不同的角色。用于构建高性能,可扩展的Web应用程序
Redis是一个高性能的key-value数据库。 Redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。
为了实现其出色的性能。Redis使用内存数据集。根据使用情况,你可以每隔一段时间将数据集转储到磁盘或通过将每个命令附加到日志来保留它。如果你只需要功能丰富的网络内存缓存,则可以选择禁用持久性。
Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
4. Redis 与其他key-value缓存产品比较
1) Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
2) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
3) Redis支持数据的备份,即master-slave模式的数据备份。
(三) Redis应用场景
1) 缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
2) 分布式集群架构中的session分离。
3) 聊天室的在线好友列表。
4) 任务队列。(秒杀、抢购、12306等等)
5) 应用排行榜。
6) 网站访问统计。
7) 数据过期处理(可以精确到毫秒)
(四) Redis说明
默认端口:6379
默认数据库:16个
服务器端命令:redis-server
客户端命令:redis-cli
切换数据库:select 0-15,例如select 2 就是切换到第二个数据库
二、 Redis安装
Redis版本规则说明:Redis约定次版本号(第一个小数点后的数字),为偶数的版本为稳定版本(例:1.2,2.0,2.2,2.4,2.6),奇数为非稳定版(例:2.9.x版本是Redis3.0曾经稳定的不稳定版本),生产环境下一般需要使用稳定版本。
1) 下载redis
http://download.redis.io/releases/
2) Redis安装环境
Redis安装一般会在Linux系统下进行安装,又因为Redis是使用c语言开发,所以需要c语言环境。
3) Redis安装
a) 第一步:在VMware中安装CentOS系统(Linux)。
b) 第二步:在Linux系统中安装c语言环境
[root@01node ~]# yum install gcc-c++ -y
c) 第三步:将redis的源码包上传到Linux系统
d) 第四步:解压源码包
[root@01node local]# tar -zxvf redis-5.0.8.tar.gz
e) 第五步:进入redis包,然后执行make命令,编译Redis的源码
f) 第六步:进入解压的src目录下,运行make test测试是否可以安装,出现绿色字体表示可以进行下一步安装,命令如下所示:
[root@localhost src]# make test
注:如果出现以下错误请进入local目录执行下列语句,安装tcl后再执行make test命令,否则请跳过以下步骤
进入local目录
[root@01node redis]# cd ../
下载tcl包
[root@01node local]# wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
[root@01node local]# tar xzvf tcl8.6.1-src.tar.gz [root@01node local]# cd /usr/local/tcl8.6.1/unix/ [root@01node unix]# ./configure [root@01node unix]# make [root@01node unix]# make install
g) 第七步:安装
[root@01node src]# make PREFIX=/usr/local/redis install
三、 Redis启动、测试和关闭
安装完Redis后下一步就是启动它。在启动之前需要先了解Redis包含的可执行文件有哪些,如下表所示。使用时直接在命令行中输入程序名称即可执行。
(一) 第一种启动方式
进入Redis的安装目录,进入bin目录下,运行redis-server
这样其实已经启动成功了,但是这属于前端启动,启动redis之后,我们的控制台就不能进行任何操作了。只能ctrl+c停止启动。
(二) 第二种启动方式:后端启动
首先编辑redis.conf配置文件,找到daemonize no将其改为yes
[root@01node bin]# cd ../ [root@01node redis]# vi redis.conf
重新加载配置文件,再次启动
[root@01node redis]# ./bin/redis-server ./redis.conf
这样redis就启动了,可以通过ps -ef | grep -i redis来查看是否启动
[root@01node redis]# ps -ef | grep -i redis
(三) Redis简单测试
[root@01node redis]# ./bin/redis-cli #启动客户端 127.0.0.1:6379> ping #测试网络是否畅通 PONG 127.0.0.1:6379> set name zhangsan # 通过键值对的方式定义name的值为zhangsan OK 127.0.0.1:6379> get name #通过键获取对应的值 "zhangsan" 127.0.0.1:6379> keys * #获取所有的键信息 1) "name" 127.0.0.1:6379> del name #删除键 (integer) 1 127.0.0.1:6379> keys * (empty list or set) 127.0.0.1:6379> exit #退出客户端
(四) Redis关闭
[root@localhost redis]# ./bin/redis-cli shutdown
四、 Redis入门
(一) Redis基础命令
1.获得符合规则的键名列表
KEYS pattern
pattern支持glob风格通配符格式,具体规则见下表:语法说明:
示例:
首先使用SET命令建立一个名为bar的键:
redis>SET bar 1 OK
使用KEYS * 获取Redis中所有的键:
redis>KEYS *
1) “bar”
注意:
2.判断一个键是否存在
EXISTS key |
命令说明:如果键存在则返回整数类型1,否则返回0。
例如:
redis> EXISTS bar (integer) 1 redis> EXISTS noexists (integer) 0
3.删除键
DEL key[key1 key2 ......]
命令说明:可以删除一个或多个键,返回值是删除的键的个数。
例如:
redis> DEL bar (integer) 1 redis> DEL bar (integer) 0
第二次执行DEL命令时,因为bar键已经被删除,实际上并没有删除任何键,所以返回值为0。
技巧:
DEL命令的参数不支持通配符,但是可以结合Linux管道和xargs命令实现删除符合所有规则的键。比如要删除所有以‘user:’开头的键,就可以执行以下代码:
redis-cli KEYS ”users:*” | xargs redis-cli DEL
另外,由于DEL命令支持多个键作为参数,所以还可以执行:
redis-cli DEL `redis-cli KEYS ”users:*”`
得到的效果相同,但是性能更高。
4.获取键值得数据类型
TYPE key
例如:命令说明:TYPE命令用来获得键值得数据类型,返回值可能是string(字符串类型)、hash(散列类型)、list(列表类型)、set(集合类型)、zset(有序集合类型)
redis> SET foo 1 OK redis> TYPE foo string redis>LPUSH bar 1 (integer) 1 redis > TYPE bar list
#LPUSH 命令的作用是向指定的列表类型键中增加一个元素,如果键不存在则创建它。
key 相关命令:
这里特别注意KEYS命令,虽然KEYS命令速度非常快,但是当Redis中百万、千万甚至过亿数据的时候,扫描所有Redis的Key,速度仍然会下降,由于Redis是单线程模型,这将导致后面的命令阻塞直到KEYS命令执行完。
因此当Redis中存储的数据达到了一定量级(经验值从10W开始就值得注意了)的时候,必须警惕KEYS造成Redis整体性能下降。
(二) Redis支持的键值数据类型
1.字符串数据类型
字符串数据类型是Redis中最基本的数据类型,他能存储任何形式的字符串,包括二进制数据。我们可以用其存储用户的邮箱、JSON化的对象甚至是一张图片。一个字符串类型的键允许存储的数据最大容量是512MB。
字符串类型是其他4种数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如:列表类型的是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。
字符串类型-命令
1) 赋值与取值
SET key value GET key
redis> SET key hello命令说明:SET和GET是Redis中最简单的两个命令,它们实现的功能和编程语言中的读写变量相似,如key='hello'在Redis中是这样表示的:
ok 读取键值: redis> GET key “hello”
当键不存在时会返回空结果。
2) .递增数字
INCR key
例如:命令说明:INCR命令是让当前键值递增,并返回递增后的值。
redis> INCR num (integer) 1 redis> INCR num (integer) 2
当要操作的键不存在时会默认值为0,所以第一次递增后的结果是1;当键值不是整数时Redis会提示错误。
redis>SET foo lorem OK redix>INCR foo (error) ERR value is not an integer or out of range
3) 增加指定的整数
INCRBY key increment
例如:命令说明:INCRBY命令与INCR命令基本一样,只不过前者可以通过increment参数指定一次增加的数值。
redis>INCRBY bar 2 (integer) 2 redix>INCRBY bar 3 (integer) 5
4) 减少指定的整数
DECR key
例如:命令说明:DECR命令与INCR命令用法相同,只不过是让键值递减。
redis>DECR bar (integer)4
DECRBY命令与INCRBY命令用法也是相同的。
DECRBY key increment
5) 增加指定的浮点数数
INCRBYFLOAT key increment
命令说明:INCRBYFLOAT命令类似于INCRBY命令,差别是前者可以递增一个双精度浮点数。
例如:
redis>INCRBYFLOAT bar 2.7 “6.7” redis>INCRBYFLOAT bar 5E+4 “50006.699999999999999929”
6) 向尾部追加值
APPEND key value
例如:命令说明:APPEND 命令的作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value,相当于SET key value。返回值是追加后字符串的总长度。
redis>SET key hello OK redis>APPEND key “world” (integer) 12
7) 获取字符串长度
SRELEN key
例如:命令说明:STELEN命令命令返回键值的长度,如果键不存在则返回0。
redis>SRELEN key (integer) 12 redis>SET key 你好 OK redis>STRLEN key (integer) 6
前面提到字符串类型可以存储二进制数据,所以它可以存储任何编码的字符串。例子中的Redis接收到的是使用UTF-8编码的中文,由于“你”和“好”两个字的UTF-8编码的长度都是3,所以最后得到的长度就是6。
8) 同时获得/设置多个键值
MGET key [key2...] MSET key value [key2 value2...]
例如:命令说明:MGET/MSET命令与GET/SET命令相似,不过MGET/MSET可以同时获得/设置多个键的键值。
redis>MSET key1 v1 key2 v2 key3 v3 OK redis>GET key2 “v2” redis>MGET key1 key3 1) “v1” 2) “v2”
9) 位操作
GETBIT key offset SETBIT key offset value BITCOUNT key [start[ [end[ BITOP operation destkey key [key...]
例如:命令说明:一个字节由8个二进制组成,Redis提供了4个命令可以直接对二进制位进行操作。
redis>SET foo bar //将foo键赋值为bar OK
bar的3个字母“b”、“a”、“r”对应的ASCII码分别是98、97、114,转换成二进制后分别为1100010、1100001、1110010,所以foo键中的二进制位结构如下所示:
b |
a |
r |
|||||||||||||||||||||
0 |
1 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
GETBIT命令可以获得一个字符串类型键指定位置的二进制位的值(0或1),索引从0开始:
redis>GETBIT foo 0 (integer) 0 redis>GETBIT foo 6 (integer) 1
如果想要获取的二进制位的索引超出了键值的二进制位的实际长度则默认位值是0。
redis>GETBIT foo 100000 (integer) 0
SETBIT命令可以设置字符串类型键指定位置的二进制位的值,返回值是该位置的旧值。例如将foo键值设置为arr,可以通过位操作将foo键的二进制位的索引第6位设为0,第七位设为1。
redis>SETBIT foo 6 0 (integer) 1 redis>SETBIT foo 7 1 (integer) 0 redis>GET foo ”arr“ redis>SETBIT nofoo 10 1 (integer) 0 redis>GETBIT nofoo 5 (integer) 0
如果要设置的位置超过了键值的二进制位的长度,SETBIT命令会自动将中间的二进制位设置为0,同理设置一个不存在的键的指定二进制位的值会自动将其前面的位赋值为0。
BITTOP命令可以对多个字符串类型键进行位运算,并将结果存储在destkey参数指定的键中。BITTOP命令支持的运算符操作有AND、OR 、XOR和NOT。例如:对bar和aar进行OR运算。
redis>SET foo1 bar OK redis>SET foo2 aar OK redis> BITTOP OR res foo1 foo2 (integer) 3 redis>GET res “car”
BITTOP命令OR运算过程,如下图:
2.散列数据类型
前面已经知道Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他的数据类型,换句话说,散列类型不能嵌套其他的数据类型。一个散列类型键可以包含至多232-1个字段。
散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、name和price的3个字段来存储该车辆的颜色、名称和价格。存储结构如图所示:
除了散列类型,Redis的其他数据类型同样不支持数据类型嵌套。比如集合类型的每个元素都只能是字符串,不能是另一个集合或者散列表等。
数据以二维表的形式存储,要求所有的记录都拥有同样的属性,无法单独为某一条记录增减属性
思考
为ID为1的汽车增加生产日期属性,例如:
ID |
color |
name |
price |
date |
1 |
黑色 |
宝马 |
100万 |
2018年10月1日 |
2 |
白色 |
奥迪 |
90万 |
|
3 |
蓝色 |
宾利 |
600万 |
|
对于ID为2和3的两条记录而言date字段是冗余的。可想而知当不同的记录需要不同的属性时,表的字段数量会越来越多以至于难以维护。而且当使用ORM将关系数据库中的对象实体映射成程序中的实体时,修改表的结构往往意味着要中断服务。为了防止这些问题,在关系数据库中存储这种半结构化数据还需要额外的表。
而Redis的散列类型则不存在这个问题。虽然我们在上图中描述了汽车对象的存储结构,但是这个结构只是人为的约定,Redis并不要求每个键都依据此结构存储,我们完全可以自由的为任何键增减字段而不影响其他键。
散列类型-命令
1) 赋值与取值
HSET key field value HGET key field HMSET key field value [field value...] HMSET key field[field...] HGETALL key
redis> HSET car price 500命令说明:HSET命令用来给字段赋值,而HGET命令用来获得字段的值。用法如下:
(integer)1 redis> HSET car price 500 (integer)1 redis> HSET car price 500 (integer)1
HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字段是否存在来决定要执行的是插入操作(insert)还是更新操作(update)。当执行的是插入操作时(即之前的字段不存在)HSET命令会返回1,当执行的更新操作时(即之前的字段已经存在)HSET命令会返回0。更进一步,当键本身不存在时,HSET命令还会自动建立它。
当需要同时设置多个字段的值时,可以使用HMSET命令。例如:
HSET key field1 value1 HSET key field2 value2
使用HMSET命令可以改写成:
HMSET key field1 value1 field2 value2
redis> HMGET car price name同样的,HMGET命令可以同时获得多个字段的值:
1)”500” 2) “BMW”
如果想获取键中所有字段和字段值却不知道键中有哪些字段时,可以使用HGETALL命令。例如:
redis> HGETALL car 1)”price” 2) “500” 3)”name” 4) “BMW”
2) 判断字段是否存在
HEXISTS key field
例如:命令说明:HEXISTS命令用来判断一个字段是否存在,如果存在则返回1,否则返回0(如果键不存在也会返回0)。
redis> HEXISTS car model (integer) 0 redis> HSET car model C200 (integer) 1 redis> HEXISTS car model (integer) 1
3) 当字段不存在时赋值
HSETNX key field value
其实现可以表示为如下伪代码:命令说明:HSETNX命令与HSET命令类似,区别在于如果字段已经存在,HSETNX命令将不执行任何操作。
def hsetnx ($key, $field,$value) $isExists = HEXISTS $key ,$field if $isExists is 0 HSET $key ,$field,$value return 1 else return 0
4) 增加数字
HINCRBY key field increment
例如:命令说明:HINCRBY命令与字符串类型的INCRBY命令类似,可以使字段值增加指定的整数,散列类型没有HINCR命令,但是可以通过HINCRBY key field 1来实现。
redis> HINCRBY person score 60 (integer) 0
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。
5) 删除字段
HDEL key field [field…]
例如:命令说明: HDEL命令可以删除一个或者多个字段,返回值是被删除的字段个数。
redis> HDEL car price (integer) 1 redis> HDEL car price (integer) 0
6) 只获得字段名或字段值
HKEYS key HVALS key
例如:命令说明: 有时仅仅需要获取键中所有的字段的名字或者所有的字段值,那么可以使用HKEYS或HVALS命令。
redis> HKEYS car 1)”name” 2)”model” redis> HVALS car 1)”bmw” 2)”C200”
7) 获得字段数量
HLEN key
redis> HLEN car例如:
(integer)2
3.列表类型
列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。
列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时间复杂度为o(1),获得越接近两端的元素速度就越快。这意味着即使是一个有几千万个元素的列表,获取头部或者尾部的10条记录也是极快的(和从只有20个元素的列表中获取头部或尾部的10条记录的速度是一样的)。
不过使用链表的代价是通过索引访问元素比较慢,但是新插入的数据直接从队尾插入,不需要管中间有多少数据。这一特性使列表类型能够快速的完成关系数据库难以应付的场景,如:社交网站的新鲜事,我们关心的只是最新的内容,使用列表类型存储,即使新鲜事的总数达到几千万个,获取其中最新的100条数据也是极快的。同样因为在两端插入记录的时间复杂度是o(1),列表类型也适合来记录日志,可以保证加入新日志的速度不会受到已有日志数量的影响。借助列表类型,Redis还可以作为队列使用。
与散列类型键最多能容纳的字段数量相同,一个列表类型键最多能容纳232-1个元素。
设想在iPad mini发售当天有1000个人在三里屯的苹果店排队等候购买,这是苹果公司宣布为了感谢大家的排队支持,巨额东奖励排在第486位的顾客一部免费的iPad mini。为了找到第486位顾客,工作人员不得不从队首一个一个数到第486位。但同时,无论队伍多长,新来的人想要加入队伍直接排在队尾即可,和队伍里有多少人没有任何的关系。这种情景与列表类型的特性很相似。
1.向列表两端增加元素
LPUSH key value [value...] RPUSH key value [value...]
例如:命令说明:LPUSH命令用了来向列表左边增加元素,返回值表示增加元素后列表的长度。
redis> LPUSH numbers 1 (integer) 1 LPUSH命令还支持同时增加多个元素,例如: redis> LPUSH numbers 2 3 (integer) 3
插入数据时LPUSH会向列表左边加入“2”,然后再加入“3”。
向列表右边增加元素,使用RPUSH命令,其用法与LPUSH命令一样。
redis> RPUSH numbers 0 -1 (integer) 5
此时numbers键中的数据如下所示:
2.从列表两端弹出元素
LPOP key RPOP key
例如:从numbers列表的左边弹出一个元素(也就是“3”)命令说明:有进有出,LPOP命令可以从列表左边弹出一个元素。LPOP命令执行两步操作:第一步是将列表左边的元素从列表中移除,第二步是返回被移除的元素值。
redis> LPOP numbers ”3”
同样,RPOP命令可以从列表右边弹出一个元素:
redis> RPOP numbers ”-1”
结合上边提到的4个命令可以使用列表类型来模拟栈和队列的操作,如果想要把列表当做“栈”,则搭配使用LPUSH和LPOP或RPUSH和RPOP;如果想当成队列,则搭配使用LPUSH和RPOP或RPUSH和LPOP。
3.获取列表中元素的个数
LLEN key
命令说明:当键不存在时LLEN会返回0,LLEN命令的功能类似于SQL语句SELECT COUNT(*) FROM table_name,但是LLEN的时间复杂度为O(1),使用时Redis会直接读取现成的值,而不需要象部分关系数据库(如使用InnoDB存储引擎的MYSQL表)那样需要遍历一遍数据表来统计条目数量。
例如:
redis> LLEN numbers (integer) 3
4.获得列表片段
LRANGE key start stop
例如:命令说明:LRANGE命令是列表类型最常用的命令之一,它能够获得列表中的某一片段。LRANGE命令将返回索引从start到stop之间的所有元素(包含两端的元素)。Redis的列表起始索引为0。
redis>LRANGE numbers 0 2 1)”2” 2)”1” 3)”0”
LRANGE命令也支持负索引,表示从右边开始计算序数,如“-1”表示最右边第一个元素,“-2”表示最右边第二个元素,以此类推:
redis>LRANGE numbers -2 -1 1)”1” 2)”0”
另外一些特殊情况如下:
1.如果start的索引位置比stop的索引位置靠后,则会返回空列表;
2.如果stop大于实际的索引范围,则会返回到列表最右边的元素。
redis>LRANGE numbers 1 999 1)”1” 2)”0”
LRANGE numbers 0 -1 可以获得列表中所有的元素。
5.删除列表中指定的值
LREM key count value
(1)当count>0 时LREM命令会从列表左边开始删除前count个值为value的元素。命令说明:LREM命令会删除列表中前count个值为value的元素,返回值是实际删除的元素个数,根据count值的不同,LREM命令的执行方式略有差异。
(2)当count<0时LREM命令会从列表右边开始删除前count个值为value的元素。
(3)当count=0时LREM命令会删除所有值为value的元素。
例如:
redis>RPUSH numbers 2 (integer) 4 redis>LRANGE numbers 0 -1 1)“2” 2)“1” 3)“0” 4)“2”
#从右边开始删除第一个值为“2”的元素
redis>LREM numbers -1 2 (integer) 1 redis>LRANGE numbers 0 -1 1)“2” 2)“1” 3)“0”
6.获得/设置指定索引的元素值
LINDEX key value LSET key index value
例如:命令说明:如果要将列表类型当作数组来用,LINDEX命令是必不可少的。LINDEX命令用来返回指定索引的元素,索引从0开始。
redis>LINDEX numbers 0 “2”
如果index是负数则表示从右边开始计算的索引,最右边元素的索引是-1。
redis>LINDEX numbers -1 “0”
LSET是另一个通过索引操作列表的命令,他会将索引为index的元素赋值为value。
例如:
redis>LSET numbers 1 7 OK redis>LINDEX numbers 1 ”7”
7.只保留列表指定片段
LTRIM key start end
例如:命令说明:LTRIM命令可以删除指定索引范围之外的所有元素,其指定列表范围的方法和LRANGE命令相同。
redis>LRANGE numbers 0 -1 1)“1” 2)“2” 3)“7” 4)“3” “0” redis>LTRIM numbers 1 2 OK redis>LRANGE numbers 0 1 1)“2” 2)“7”
LTRIM命令常和LPUSH命令一起使用用来限制列表中元素的数量,比如记录日志时只希望保留最近的100条日志,则每次加入新元素时调用一次LTRIM命令即可:
LPUSH logs $newLog LTRIM logs 0 99
8.向列表中插入元素
LINSERT key BEFORE | AFTER pivot value
例如:命令说明:LINSERT命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。LINSERT命令的返回值是插入后列表的元素个数。
redis>LRANGE numbers 0 -1 1) “2” 2) “7” 3) “0” redis>LINSERT numbers AFTER 7 3 1) “2“ 2) “7” 3) “3” 4)”0”
4.集合类型
集合的概念高中的数学课本就学习过。在集合中的每个元素都是不同的,且没有顺序。一个集合类型(set)键可以存储至多232-1个字符串。集合类型和列表类型有相似之处,但很容易将他们区分开来,如下所示:
|
集合类型 |
列表类型 |
存储内容 |
至多232-1个字符串 |
至多232-1个字符串 |
有序性 |
否 |
是 |
唯一性 |
是 |
否 |
集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是O(1)。最方便的是多个集合类型键之间还可以进行并集、交集和差集运算。
1.增加/删除元素
SADD key member[member...] SREM key member[member...]
SREM命令用来从集合中删除一个或者多个元素,并返回删除成功的个数。命令说明:SADD命令用来向集合中增加一个或者多个元素,如果键不存在则会自动创建。因为在一个集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。本命令的返回值是成功加入的元素数量(忽略的元素不计在内)。
例如:
redis>SADD letters a (integer) 1 redis>SADD letters a b c (integer) 2 redis>SREM letters c d (integer) 1
第二条SADD命令的返回值为2是因为元素“a”已经存在,所以实际上之加入了两个元素。
由于元素”d”在集合中不存在,所以只删除一个元素,返回值为1。
2.获得集合中的所有元素
SMEMBERS key
命令说明:SMEMBERS命令会返回集合中的所有元素。
例如:
redis> SMEMBERS letters 1) ”b” 2) ”a”
3.判断元素是否在集合中
SISMEMBER key member
命令说明:判断一个元素是否在集合中是一个时间复杂度为O(1)的操作,无论集合中有多少个元素,SISMEMBER命令始终可以极快的返回结果。当值存在时SISMEMBER命令返回1,当值不存在或键不存在时返回0。
例如:
redis> SISMEMBER letters a (integer) 1 redis> SISMEMBER letters b (integer) 0
4.集合间的运算
SDIFF key [key...] SINTER key [key...] SUNION key [key...]
(1)SDIFF命令用来对多个集合执行差集运算。集合A 与集合B的差集表示为A-B,代表所有属于A且不属于B的元素构成的集合。例如:
{1,2,3}-{2,3,4} = {1} {2,3,4}-{1,2,3} = {4}
SDIFF命令的使用方法如下:
redis> SADD setA 1 2 3 (integer) 3 redis> SADD setB 2 3 4 (integer) 3 redis> SDIFF setA setB 1) ”1” redis> SDIFF setB setA 1) ”4”
命令说明:3个命令都是用来集合间运算的。
SDIFF命令支持同时传入多个键,例如:
redis> SADD setC 2 3 (integer) 2 redis> SDIFF setA setB setC 1) ”1”
(2)SINTER命令用来对多个集合执行交集运算。集合A与集合B的交集表示为A∩B,代表所有属于A且属于B的元素构成的集合。例如:
{1,2,3}∩{2,3,4} = {2,3}
SINTER命令的使用方法如下:
redis> SINTER setA setB 1) ”2” 2) ”3” redis> SDIFF setA setB setC 1) ”2” 2) ”3”
SINTER命令同样支持同时
传入多个键
(3)SUNION命令用来对多个集合执行并集运算。集合A与集合B的交集表示为A∪B,代表所有属于A或属于B的元素构成的集合。例如:
{1,2,3}∪{2,3,4} = {1,2,3,4}
SINTER命令同样支持同时传入多个键,如下所示:
redis> SINTER setA setB 1) ”1” 2) ”2” 3) ”3” 4) ”4” redis> SDIFF setA setB setC 1) ”1” 2) ”2” 3) ”3” 4) ”4”
5.获得集合中元素个数
SCARD key
命令说明:SCARD命令用来获得集合中的元素个数。
例如:
redis> SMEMBERS letters 1) ”b” 2) ”a” redis> SCARD letters (integer) 2
6.进行集合运算并将结果存储
SDIFFSTORE destination key [key ...] SINTERSTORE destination key [key ...] SUNIONSTORE destination key [key ...]
SDIFFSTORE命令和SDIFF命令功能一样,唯一的区别就是前者不会直接返回运算结果,而是将结果存储在destination键中。命令说明:
SDIFFSTORE命令常用于需要进行多步集合运算的场景中,如需要先计算差集再将结果和其他键计算交集。
SINTERSTORE命令和SUNIONSTORE命令与之类似,不再赘述。
7.随机获得集合中的元素
SRANDMEMBER key [count]
还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。命令说明:SRANDMEMBER命令用来随机从集合中获取一个元素。
(1)当count为正数时,SRANDMEMBER会随机从集合里获得count个不重复的元素。如果count的值大于集合中的元素个数,则SRANDMEMBER会返回集合中的全部元素。
(2)当count为负数时,SRANDMEMBER会随机从集合里获得|count|个的元素。这些元素可能会相同。
例如:
redis> SRANDMEMBER letters ”a” redis> SRANDMEMBER letters ”b” redis> SRANDMEMBER letters ”a”
redis> SADD letters c d (integer) 2 redis> SRANDMEMBER letters 2 1)”a” 2)”b” redis> SRANDMEMBER letters 100 1)”a” 2)”b” 3)”c” 4)”d” redis> SRANDMEMBER letters -2 1)”b” 2)”b” redis> SRANDMEMBER letters -6 1)”a” 2)”b“ 3)”c” 4)”c” 5)”d” 6)”b” //目前letters集合中共有“a”,”b”,”c”,”d”4个元素
8.从集合中弹出一个元素
SPOP key
例如:命令说明:SPOP命令与LPOP命令类似,但是由于集合类型的元素是无序的,所以SPOP命令会从集合中随机选择一个元素弹出。
redis> SPOP letters ”b” redis> SMEMBERS letters 1)”a” 2)”c” 3)”d”
前边学过LPOP命令作用是从列表左边弹出一个元素(即返回元素的值并删除它)
5.有序集合类型
有序集合类型(sorted set)的特点就是“有序”,与集合的区别也在于“有序”二字。在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能获得分数最高(最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同。
有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得他们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获得靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会较慢,所以它适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
(2)有序集合类型是使用散列表和跳跃表(skip list)实现的,所以即使读取位于中间部分的数据速度也很快(时间复杂度是O(log(N))。
(3)列表中不能简单的调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。
(4)有序集合类型要比列表类型更耗费内存。
有序集合类型是Redis的5种数据类型中最高级的类型。
1.增加数字
HINCRBY key field increment
例如:命令说明:HINCRBY命令与字符串类型的INCRBY命令类似,可以使字段值增加指定的整数,散列类型没有HINCR命令,但是可以通过HINCRBY key field 1来实现。
redis> HINCRBY person score 60 (integer) 0
之前person键不存在,HINCRBY命令会自动建立该键并默认score字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。
2.删除字段
HDEL key field [field…]
例如:命令说明: HDEL命令可以删除一个或者多个字段,返回值是被删除的字段个数。
redis> HDEL car price (integer) 1 redis> HDEL car price (integer) 0
3.只获得字段名或字段值
HKEYS key HVALS key
命令说明: 有时仅仅需要获取键中所有的字段的名字或者所有的字段值,那么可以使用HKEYS或HVALS命令。
例如:
redis> HKEYS car 1)”name” 2)”model” redis> HVALS car 1)”bmw” 2)”C200”
4.获得字段数量
HLEN key
redis> HLEN car例如:
(integer)2
INCR key |