NoSQL
一、NoSql
NoSQL = Not Only SQL(不仅仅是SQL)非关系型数据库
二、为什么需要NoSQL
1、web1.0
在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。单机MySql足以满足。
2、web2.0
着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题
![](https://i-blog.csdnimg.cn/blog_migrate/d92a7e66e395184272a45e384af80633.png)
NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
NoSQL的特点
1、易扩展
2、灵活的数据模型
3、大数据量,高性能
4、高可用
![](https://i-blog.csdnimg.cn/blog_migrate/d18210d6749d10e64c0a7f4d57ccfad4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d3f02d39fd694ad79f91121497539d87.png)
三、CAP原理
什么是CAP
C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance(分区容错性)
1、CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
2、分区容错性是必须要实现的;
3、根据CAP原理,将NoSQL数据库分成了三大类:
①CA,单点集群,满足一致性,可用性的系统,通常在扩展性上不太强大;(传统Oracle数据库)
②CP,满足一致性,分区容错性的系统,通常性能不是特别高;(Redis,Mongodb)
③AP,满足可用性,分区容错性的系统,通常可能对一致性要求低一些;(大多数网站架构的选择)
四、 NoSQL为什么不能代替数据库
① NoSQL 的数据主要存储在内存中,而数据库主要是磁盘。
② NoSQL 数据库结构比较简单,虽然能处理很多的问题,但是其功能毕竟有限,不如数据库的SQL语句强大,支持更为复杂的计算
③NoSQL 并不完全安全稳定,由于它基于内存,一旦停电或者机器故障数据就很容易丢失,其持久化能力也是有限的,而基于磁盘的数据库则不会出现这样的问题
④NoSQL 其数据完整性、事务能力、安全性、可靠性以及可扩展性都远不及数据库
Redis
一、Redis介绍
REmote DIctionary Server(远程字典服务器) 是一个由Salvatore Sanfilippo写的key-value存储系统。
Redis是一个开源的,使用 C语言编写的、遵守BSD协议、支持网络、可基于内存亦可持久化NoSQL数据库,并提供多种语言的API。
键的类型只能为字符串,值支持5种数据类型:字符串、列表、集合、散列表、有序集合
二、Redis优势
Ø 性能极高 – Redis 读的速度是110000次/s,写的速度是81000次/s 。
Ø 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及Ordered Sets 数据类型操作。
Ø 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
Ø 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
二、Redis应用场景
①缓存
在对数据库的读/写操作中,读操作远超写操作,一般是9:1到7:3的比例,所以需要读的可能性比写的可能性多得多。
当发送SQL去数据进行读取时,数据库就会去磁盘把对应的数据索引取回来,而索引磁盘是一个相对缓慢的过程。如果把数据直接放在运行在内存中的Redis服务器上,那么就不需要去读/写磁盘了,而是直接读取内存,显然速度会快得多,而且会极大减轻数据库的压力。
②高速读/写场合
高速读/写场合例如:秒杀商品、抢红包、抢票等。这类场合在一瞬间成千上万的请求就会达到服务器,如果使用的数据库,很容易造成数据库瘫痪。
解决办法是异步写入数据库,即在高速读/写的场合单单使用 Redis 去应对,把这些需要高速读/写的数据缓存到 Redis 中,而在满足一定的条件下,触发这些缓存的数据写入数据库中。
![](https://i-blog.csdnimg.cn/blog_migrate/88d8da428a7a1cc7b948d22840fe3a5c.png)
三、Redis数据库
Redis 命令参考:http://redisdoc.com/
1、默认16个数据库,从0到15,初始默认为0号库
2、select命令切换数据库:select 0
3、dbsize查看当前数据库的key的数量
4、flushdb:清空当前数据库
5、flushall:清空16个库
Key(键)
1、keys * :列出所有键
2、exists key的名字:判断某个key是否存在
3、move key db:移动当前库的key到目标库db
4、expire key 秒数:为给定的key设置过期时间
5、ttl key:查看还有多少秒过期,-1表示
6、type key:查看你的key是什么类型
五大数据类型
一、string(字符串)
string字符串(单值单value)
字符串类型是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,这意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。在Redis中字符串类型的Value最多可以容纳的数据长度是512M。
存储形式:
![](https://i-blog.csdnimg.cn/blog_migrate/6a4b7e7335da6fbe1f0929924f9565ae.png)
1、set:将字符串值 value 关联到 key,如果 key 已经持有其他值, SET 就覆写旧值
2、get:返回与键 key 相关联的字符串值。如果键 key 不存在, 那么返回特殊值 nil ;如果键 key 的值并非字符串类型, 那么返回一个错误。
3、del:删除key
4、append:如果键 key 已经存在并且它的值是一个字符串, APPEND 命令将把 value 追加到键 key 现有值的末尾。如果 key 不存在, APPEND 就简单地将键 key 的值设为 value , 就像执行 SET key value 一样。
5、strlen:返回键 key 储存的字符串值的长度。当键 key 不存在时, 命令返回 0 。当 key 储存的不是字符串值时, 返回一个错误。
6、Incr/decr:为键 key 储存的数字值加1/减1,如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行加1/减1的操作。如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。
7、incrby/decrby:为键 key 储存的数字值加上(减去)增量 increment 。如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行。如果键 key 储存的值不能被解释为数字, 那么将返回一个错误。
8、getrange:获取指定区间范围内的值。字符串的截取范围由 start 和 end 两个偏移量决定 (包括 start 和 end 在内)。负数偏移量表示从字符串的末尾开始计数, -1 表示最后一个字符, -2 表示倒数第二个字符, 以此类推。
9、setrange:设置指定区间范围内的值,格式是setrange key 偏移量 具体值
10、setex(set with expire)键秒值:设置带过期时间的key,动态设置。setex 键 秒值 值
11、setnx(set if not exist):只有在 key 不存在时设置 key 的值,若键 key 已经存在, 则 SETNX 命令不做任何动作。命令在设置成功时返回 1 , 设置失败时返回 0 。
12、mset:同时为多个键设置值。如果某个给定键已经存在, 那么 MSET 将使用新值去覆盖旧值
13、mget:返回给定的一个或多个字符串键的值。如果给定的字符串键里面,有某个键不存在, 那么这个键的值将以特殊值 nil 表示。MGET 命令将返回一个列表, 列表中包含了所有给定键的值。
14、msetnx:当且仅当所有给定键都不存在时,为所有给定键设置值。即使只有一个给定键已经存在, MSETNX 命令也会拒绝执行。当所有给定键都设置成功时, 命令返回 1 ; 如果因为某个给定键已经存在而导致设置未能成功执行, 那么命令返回 0 。
15、getset:将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值返回给定键 key 的旧值。
如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。当键 key 存在但不是字符串类型时, 命令返回一个错误。
二、list(列表)
列表的元素类型为string,按照插入顺序排序,元素有索引。它是一个字符串链表,left、right都可以插入添加。
如果键不存在,创建新的链表;
如果键已存在,新增内容;
如果值全移除,对应的键也就消失了。
存储形式:
![](https://i-blog.csdnimg.cn/blog_migrate/da7d8ec4b577985f9767b08977a83739.png)
1、 lpush:将一个或多个值 value 插入到列表 key 的表头。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头:
比如:执行命令 LPUSH mylist a b c ,列表的值将是 c b a 。执行 LPUSH 命令后,列表的长度。
2、rpush:将一个或多个值 value 插入到列表 key 的表尾(最右边)。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:
比如:执行 RPUSH mylist a b c ,得出的结果列表为 a b c 。执行 RPUSH 操作后,表的长度
3、 lrange:返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
4、lpop/rpop:移除并返回列表 key 的头/尾元素。当 key 不存在时,返回 nil
5、lindex:返回列表 key 中,下标为 index 的元素。返回列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内返回 nil 。
6、 llen:返回列表 key 的长度。如果 key 不存在,则 key 被解释为一个空列表,返回 0。如果 key 不是列表类型,返回一个错误。
7、lrem:根据参数 count 的值,移除列表中与参数 value 相等的元素
count 的值可以是以下几种:
count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
count = 0 : 移除表中所有与 value 相等的值。
返回值:被移除元素的数量。 当 key 不存在时返回
8、 ltrim:对一个列表进行修剪(trim),让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
9、rpoplpush :移除列表的最后一个元素,并将该元素添加到另一个列表并返回
10、lset:将列表 key 下标为 index 的元素的值设置为 value
11、linsert:将值 value 插入到列表 key 当中,位于 值 之前或之后。
三、set(集合)
元素为string类型,元素具有唯一性,不重复。
存储形式:
![](https://i-blog.csdnimg.cn/blog_migrate/e292fb23e3f7f6774e0a21ee4906c8ab.png)
1、sadd:将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。
2、smembers:返回集合 key 中的所有成员。
3、sismember:判断元素是否集合的成员。如果元素是集合的成员,返回 1 。如果元素不是集合的成员,或不存在,返回 0 。
4、scard:返回集合中元素的数量, 当 key 不存在时,返回 0
5、srem:移除集合 key 中的一个或多个 member 元素,不存在的 member
元素会被忽略
6、srandmember:随机返回指定数量的元素。
7、spop:移除并返回集合中的一个随机元素。
8、smove:将 元素从 一个集合移动到 另一个集合 。
9、sdiff:差集
10、sinter:交集
11、sunion:并集
四、zset(有序集合)
元素为string类型,元素具有唯一性,每个元素都会关联一个double(双精度)类型的score,表示权重,通过权重将元素从左到右排序。
即:
在set基础上,加一个score值。
set是k1 v1 v2 v3,
zset是k1 score1 v1 score2 v2
1、 zadd:将一个或多个 member 元素及其 score 值加入到有序集 key 当中。如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。score 值可以是整数值或双精度浮点数。
2、zrange:返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序。具有相同 score 值的成员按字典序来排列。
3、zrangebyscore :返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。区间的取值使用闭区间 (小于等于或大于等于),可以通过给参数前增加 ( 符号来使用可选的开区间(小于或大于)。
4、 zrem:移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
5、zcard:返回有序集 key 的个数。
6、zcount:返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等
于 min 或 max )的成员的数量。
7、zrevrank:返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值
递减(从大到小)排序。排名以 0 为底,也就是说, score 值最大的成员排名为 0 。
8、zrevrange:返回有序集 key 中,指定区间内的成员。
9、zrevrangebyscore :返回有序集 key 中, score 值介于 max 和 min 之间(默认包
括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。
五、hash(哈希)
可以理解为首先有一个主key,在这个主key下数据以key-value形式存储,值的类型也是String
存储形式:
![](https://i-blog.csdnimg.cn/blog_migrate/3535e618066e990d0944a5f3c05e79fb.png)
1、hset:将哈希表 hash 中域 field 的值设置为 value 。
2、hget:返回哈希表中给定域的值。
3、hmset:同时将多个 field-value (域-值)对设置到哈希表 key 中。此命令会覆盖哈希表中已存在的域。
4、hmget:返回哈希表 key 中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个 nil 值。
5、hgetall:返回哈希表 key 中,所有的域和值。
6、hdel:删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
7、hlen:返回哈希表 key 中域的数量。当 key 不存在时,返回 0 。
8、hexists:检查给定域 field 是否存在于哈希表 hash 当中。在给定域存
在时返回 1 , 在给定域不存在时返回 0 。
9、hkeys:返回哈希表 key 中的所有域。
10、hvals:返回哈希表 key 中所有域的值。
11、hincrby:为哈希表 key 中的域 field 的值加上增量 increment 。
12、hincrbyfloat:为哈希表 key 中的域 field 加上浮点数增量 increment 。
13、hsetnx:当且仅当域 field 尚未存在于哈希表的情况下, 将它的值设置
为 value 。如果给定域已经存在于哈希表当中, 那么将放弃执行设置操作。