Redis
- Redis 简介
- 非关系型数据库(NOSQL)
- 非关系型数据库的产生背景
- 非关系型数据库的种类
- 键值(Key-Value)存储数据库
- 文档型数据库
- 图形(Graph)数据库
- Redis特点/优势
- Redis缺点
- Redis与Mysql比较
- 非关系型数据库(NOSQL)
- Redis 基本操作
- String类型
- 赋值语法:
- 取值语法:
- 删除语法:
- 自增/自减:
- 应用场景:
- 字典类型
- 赋值语法:
- 取值语法:
- 删除语法:
- 其它语法:
- 应用场景:
- List类型
- 赋值语法
- 取值语法
- 删除语法
- 修改语法
- 高级语法
- 应用场景
- Set类型
- 赋值语法:
- 删除语法
- 差集语法
- 交集语法
- 并集语法
- 应用场景
- 有序集合(Sorted Set)
- 赋值语法:
- 取值语法:
- 删除语法:
- 应用场景:
- String类型
Redis 简介
Redis是一个开源的高性能的非关系型数据库(NOSQL)。是以键值对(key-value)的形式将数据存储在内存中。提供多种键值对的数据类型适应不同场景下的需求。同时redis的诸多高级功能使其可以胜任任务队列消息队列等不同角色。
数据库----》功能:存储数据。存储形式:key-value 数据存储位置:内存 数据类型、功能丰富。
Redis遵守"伯克利软件发行版"协议。简称BSD协议。
BSD开源协议是一个给予使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布,也允许在源代码的基础上开发商业软件发布和销售,因此是对商业集成很友好的协议。但需要尊重代码作者的著作权。
非关系型数据库(NOSQL)
非关系型数据库:数据与数据之间不存在关系。数据和数据是独立的
存储人名:set name Sam key: name value Sam
关系型数据库:MySQL
非关系型数据库的产生背景
在超高并发量的开发场景当中。关系型数据库存在以下瓶颈
mysql 数据存储在磁盘中(文件)
1.磁盘IO过于耗时,关系型数据库根本无法应付对并发读写能力要求极高的场景。
2.当数据量巨大时,在一张包含海量数据的表中查询,效率是非常低的
3.关系型数据库在事务索引外键等功能的维护上有非常大的开销。但其实在某些场景下我们并不需要这些功能.
4.表结构固定扩展性极差,系统的升级,功能的增加,往往意味着数据结构巨大变动,这一点关系型数据库也难以应付,需要新的结构化数据存储。
5.我们经常会为了查询某一数据需要编写复杂的sql语句
非关系型数据库解决了以上问题。
非关系型数据库的种类
键值(Key-Value)存储数据库
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据
列存储数据库
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.
文档型数据库
文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。
图形(Graph)数据库
图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。[2] 如:Neo4J, InfoGrid, Infinite Graph.
Redis特点/优势
a. Redis将数据存放在内存中,但是也提供了redis持久化的方式数据。
b. 以key-value形式存储,有着丰富的数据类型可以适用多种开发场景(支持list,set,zset,hash等数据结构)
c. redis性能极高能读的速度是110000次/s,写的速度是81000次/s
d. redis具有原子性,Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即多个操作也可维护其具有原子性。
e. Redis支持数据的备份,集群等高可用功能。
Redis缺点
a. 耗内存,占用内存过高。
b. 持久化。Redis直接将数据存储到内存中,要将数据保存到磁盘上,Redis可以使用两种方式实现持久化过程。定时快照(snapshot)(RDB):每隔一段时间将整个数据库写到磁盘上,每次均是写全部数据,代价非常高。第二种方式基于语句追加(aof):所有的操作指令存储到日志中。只追踪变化的数据,但是追加的log可能过大,同时所有的操作均重新执行一遍,恢复速度慢。
c. 由于数据与数据之间不存在关系无法根据一个数据查询另一数据。
Redis与Mysql比较
redis不能完全取代MySQL,Redis和MySQL各有所长,实际的开发中我们通常配合使用。mysql支持sql查询,可以实现一些关联的查询以及统计;redis对内存要求比较高在有限的条件下不能把所有数据都放在redis,mysql偏向于存数据,redis偏向于快速取数据,但redis维护复杂的数据关系时不如mysql,所以使用mysql存基本数据我们会将经常需要使用或者经常变化的数据(热门数据)单独拿出来存在redis中,而在MySQL中维系这些数据之间的关系。用redis保证高并发场景的下的高速读写。
Redis 基本操作
String类型
string是redis最基本的类型,一个key对应一个value。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型,一个键最大能存储512MB。 二进制安全是指,在传输数据时,保证二进制数据的信息安全,也就是不被篡改、破译等,如果被攻击,能够及时检测出来
二进制安全特点:
a. 编码、解码发生在客户端完成,执行效率高
b. 不需要频繁的编解码,不会出现乱码
赋值语法:
SET KEY_NAME VALUE
Redis SET 命令用于设置给定 key 的值。如果 key 已经存储值, SET 就覆写旧值,且无视类型
SETNX key value //解决分布式锁 方案之一
只有在 key 不存在时设置 key 的值。Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值
MSET key value [key value …]同时设置一个或多个 key-value 对
取值语法:
GET KEY_NAME Redis GET命令用于获取指定 key 的值。如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误。
GETRANGE key start end
用于获取存储在指定 key 中字符串的子字符串。字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)
GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
MGET key1 [key2…]获取所有(一个或多个)给定 key 的值
GETSET语法: GETSET KEY_NAME VALUE Getset 命令用于设置指定 key 的值,并返回 key 的旧值,当 key 不存在时,返回 nil
STRLEN key 返回 key 所储存的字符串值的长度
删除语法:
DEL KEY_Name 删除指定的KEY,如果存在,返回值数字类型。
自增/自减:
INCR KEY_Name
Incr 命令将 key 中储存的数字值增1。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作
自增:INCRBY KEY_Name 增量值 Incrby 命令将 key 中储存的数字加上指定的增量值
自减:DECR KEY_NAME 或 DECYBY KEY_NAME 减值 decR 命令将 key 中储存的数字减1
字符串拼接:APP KEY_NAME VALUE Append 命令用于为指定的 key 追加至末尾,如果不存在,为其赋值
应用场景:
a. String通常用于保存单个字符串或JSON字符串数据
b. 因String是二进制安全的,所以你完全可以把一个图片文件的内容作为字符串来存储
c. 计数器(常规key-value缓存应用。常规计数: 微博说, 粉丝数)INCR等指令本身就具有原子操作的特性,所以我们完全可以利用redis的INCR、INCRBY、DECR、 DECRBY等指令来实现原子计数的效果。假如,在某种场景下有3个客户端同 时读取了mynum 的值(值为2),然后对其同时进行了加1的操作,最后mynum 的值一定是5。不少网站都利用redis的这个特性来实现业务上的统计计数需求。
字典类型
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。 Redis 中每个 hash 可以存储 2^32 - 1 键值对(40多亿)可以看成具有KEY和VALUE的MAP容器,该类型非常适合于存储值对象的信息, 如:uname,upass,age等。该类型的数据仅占用很少的磁盘空间(相比于JSON)
赋值语法:
HSET KEY FIELD VALUE //为指定的KEY,设定FILD/VALUE
HMSET KEY FIELD VALUE [FIELD1,VALUE1]…… 同时将多个 field-value (于 -值) 对设置到哈希表 key 中。
取值语法:
HGET KEY FIELD //获取存储在HASH中的值,根据FIELD得到VALUE
HMGET key field[field1] //获取key所有给定字段的值
HGETALL key //返回HASH表中所有的字段和值
HKEYS key //获取所有哈希表中的字段
HLEN key //获取哈希表中字段的数量
删除语法:
HDEL KEY field1[field2] //删除一个或多个HASH表字段
其它语法:
HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值
HINCRBY key field increment
为哈希表 key 中的指定字段的整数值加上增量 increment 。
HINCRBYFLOAT key field increment
为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
HEXISTS key field //查看哈希表 key 中,指定的字段是否存在
应用场景:
(存储一个用户信息对象数据)常用于存储一个对象为什么不用string存储一个对象?hash是最接近关系数据库结构的数据类型,可以将数据库一条记录或程序中一个对象转换成hashmap存放在redis中。用户ID为查找key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:
第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。
第二种方法是这个用户信息对象有多少成员就存成多少个key-value对象,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。总结:Redis提供的Hash很好地解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口
List类型
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含 2^32 - 1 个元素 (4294967295, 每个列表超过40亿个元素) 类似JAVA中LinkedList。那这个链表应该是LinkedList。
赋值语法
LPUSH key value1 [value2] //将一个或多个值插入到列表头部(从左侧添加)
RPUSH key value1 [value2] //在列表中添加一个或多个值(从右侧添加)
LPUSHX key value //将一个值插入到已存在的列表头部。如果列表不在,操作无效
RPUSHX key value //一个值插入已存在的列表尾部(最右边)。如果列表不在,操作无效。
取值语法
LLEN key //获取列表长度
LINDEX key index //通过索引获取列表中的元素
LRANGE key start stop //获取列表指定范围内的元素
注意:返回列表中指定区间内的元素,区间以偏移量 START 和 指定。 其中 0 表示列表的第一个元素,1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。start: 页大小(页数-1) stop : (页大小页数)-1
删除语法
LPOP key 移出并获取列表的第一个元素(从左侧删除)
RPOP key 移除列表的最后一个元素,返回值为移除的元素(从右侧删除)
BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或 发现可弹出元素为止。
实例
redis 127.0.0.1:6379> BLPOP list1 100
在以上实例中,操作会被阻塞,如果指定的列表 key list1 存在数据则会返回第一个元素,否则在等待100秒后会返回 nil 。
BRPOP key1 [key2 ] timeout
移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
LTRIM key start stop
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
修改语法
LSET key index value 通过索引设置列表元素的值
LINSERT key BEFORE|AFTER world value 在列表的元素前或者后插 入元素描述:将值 value 插入到列表 key 当中,位于值 world 之前或之后。
高级语法
RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
示例描述:
RPOPLPUSH a1 a2 //a1的最后元素移到a2的左侧
RPOPLPUSH a1 a1 //循环列表,将最后元素移到最左侧
BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
应用场景
对数据量大的集合数据删减
列表数据显示、关注列表、粉丝列表、留言评价等…分页、热点新闻(Top5)等利用LRANGE还可以很方便的实现分页的功能,在博客系统中,每篇博文的评论也可以存入一个单独的list中。
任务队列
(list通常用来实现一个消息队列,而且可以确保先后顺序,不必像MySQL那样还需要通过ORDER BY来进行排序)任务队列介绍(生产者和消费者模式): 在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些,通过将待执行任务的相关信息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能能完成的操作,这种将工作交给任务处理器来执行的做法被称为任务队列(task queue)。
Set类型
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。类似于JAVA中的 Hashtable集合redis的集合对象set的底层存储结构特别神奇,底层使用了intset和hashtable两种数据结构存储的,intset我们可以理解为数组,hashtable就是普通的哈希表(key为set的值,value为null)。intset内部其实是一个数组(int8_t coentents[]数组),而且存储数据的时候是有序的,因为在查找数据的时候是通过二分查找来实现的。
赋值语法:
SADD key member1 [member2] 向集合添加一个或多个成员
取值语法:
SCARD key 获取集合的成员数
SMEMBERS key 返回集合中的所有成员
SISMEMBER key member 判断 member 元素是否是集合 key 的成员(开发中:验证是否存在判断)
SRANDMEMBER key [count] 返回集合中一个或多个随机数
删除语法
SREM key member1 [member2] 移除集合中一个或多个成员
SPOP key [count] 移除并返回集合中的一个随机元素
SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合
差集语法
SDIFF key1 [key2] 返回给定所有集合的差集(左侧)
SDIFFSTORE destination key1 [key2] 返回给定所有集合的差集并存储在destination 中
交集语法
SINTER key1 [key2] 返回给定所有集合的交集(共有数据)
SINTERSTORE destination key1 [key2] 返回给定所有集合的交集并存储在 destination 中
并集语法
SUNION key1 [key2] 返回所有给定集合的并集
SUNIONSTORE destination key1 [key2] 所有给定集合的并集存储在destination 集合中
应用场景
常应用于:对两个集合间的数据[计算]进行交集、并集、差集运算
a. 以非常方便的实现如共同关注、共同喜好、二度好友等功能。对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存储到一个新的集合中。
b. 利用唯一性,可以统计访问网站的所有独立 IP。
有序集合(Sorted Set)
a. Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
b. 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
c. 有序集合的成员是唯一的,但分数(score)却可以重复。
d. 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。Redis的ZSet是有序、且不重复 (很多时候,我们都将redis中的有序集合叫做zsets,这是因为在redis中,有序集合相关的操作指令都是以z开头的)
赋值语法:
ZADD key score1 member1 [score2 member2]
向有序集合添加一个或多个成员,或者更新已存在成员的分数
取值语法:
ZCARD key 获取有序集合的成员数
ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
ZRANK key member 返回有序集合中指定成员的索引
ZRANGE key start stop [WITHSCORES]
通过索引区间返回有序集合成指定区间内的成员(低到高)
ZREVRANGE key start stop [WITHSCORES]
返回有序集中指定区间内的成员,通过索引,分数从高到底
删除语法:
del key 移除集合
ZREM key member [member …] 移除有序集合中的一个或多个成员
ZREMRANGEBYRANK key start stop 移除有序集合中给定的排名区间的所有成员(第一名是0)(低到高排序)
ZREMRANGEBYSCORE key min max 移除有序集合中给定的分数区间的所有成员
应用场景:
a. 比如微博的 的实时新闻可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
b. 比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。
c. 还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。有序集合(Sorted Set)