![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083625347-1229269954.png)
一、Nosql 数据库
1 什么是 NoSQL
NoSQL(NoSQL = Not Only SQL),意即“不仅仅是 SQL”,是一项全新的数据库理念,泛指非关系型的数据库。
2 为什么需要 NoSQL
随着互联网 web2.0 网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速。而传统的关系数据库在应付 web2.0 网站,特别是超大规模和高并发的 SNS 类型的 web2.0 纯动态网站己经显得力不从心,暴露了很多难以克服的问题
例如:
1)High performance -对数据库高并发读写的需求
web2.0 网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付 上万次 SQL 查询还勉强顶得住,但是应付上万次 SQL 写数据请求,硬盘 10 就己经无法承受了。其实 对于普通的 BBS 网站,往往也存在对高并发写请求的需求,例如网站的实时统计在线用户状态,记录热门帖子的点击次数,投票计数等,因此这是一个相当普遍的需求。
2)Huge Storage -对海量数据的高效率存储和访问的需求
类似 Facebook,twitter, Friendfeed 这样的 SNS 网站,每天用户产生海量的用户动态,以Friendfeed为例,一个月就达到了 2.5 亿条用户动态,对于关系数据库来说,在一张 2.5 亿条记录的表里面进行 SQL 查询,效率是极其低下乃至不可忍受的。再例如大型 web 网站的用户登录系统,例如腾讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。
3)High Scalability && High Availability-对数据库的高可扩展性和高可用性的需求在基于 web 的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日倶增的时候,你的数据库却没有办法像 web server 和 app server 那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供 24 小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,为什么数
据库不能通过不断的添加服务器节点来实现扩展呢?
总结:
NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
3 NoSQL 数据库的四大分类
1)键值(Key-Value)存储数据库
相关产品:Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型应用:内容缓存,主要用于处理大量数据的高访问负载。
数据模型:一系列键值对
优势:快速查询
劣势:存储的数据缺少结构化
2)列存储数据库
相关产品:Cassandra, HBase, Riak
典型应用:分布式的文件系统
数据模型:以列簇式存储,将同一列数据存在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能相对局限
3)文档型数据库
相关产品:CouchDB、MongoDB
典型应用:Web 应用(与 Key-Value 类似,Value 是结构化的)
数据模型:一系列键值对
优势:数据结构要求不严格
劣势:查询性能不高,而且缺乏统一的查询语法
4)图形(Graph)数据库
相关数据库:Neo4J> InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优势:利用图结构相关算法。
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。
4 N0SQL 特点
在大数据存取上具备关系型数据库无法比拟的性能优势,例如:
1)易扩展
NoSQL 数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之
间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。
2)大数据量,高性能
NoSQL 数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它 的
无关系性,数据库的结构简单。
3)灵活的数据模型NoSQL 无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数
据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是 一个
噩梦。这点在大数据量的 Web2.0 时代尤其明显。
4)高可用
NoSQL 在不太影响性能的情况,就可以方便的实现高可用的架构。比如 Cassandra, HBase
模型,通过复制模型也能实现高可用。
综上所述,NoSQL 的非关系特性使其成为了后 Web2.0 时代的宠儿,助力大型 Web2.0 网站的再次起飞,是
一项全新的数据库革命性运动。
二、Redis
1.简介
2008 年,意大利的一家创业公司 Merzia 推出了一款基于 MySQL 的网站实时统计系统
LL00GG, 然而没过多久该公司的创始人 Salvatore Sanfilippo 便对 MySQL 的性能感到失望,
于是他决定亲自为 LL00GG 量身定做一个数据库,并于 2009 年开发完成,这个数据库就是
Redis。不过 SalvatoreSanfilippo 并不满足只将 Redis 用于 LL00GG 这一款产品,而是希望更
多的人使用它,于是在同一年 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。
2.什么是 Redis
Redis 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种
键值数据类型来适应不同场景下的存储需求,目前为止 Redis 支持的键值数据类型如下:
字符串类型
散列类型
列表类型
集合类型
有序集合类型。
官方提供测试数据: 50 个并发执行 100000 个请求,读的速度是 110000 次/s,写的速度是
81000 次/s。数据仅供参考,根据服务器配置会有不同结果。
3.redis 的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
聊天室的在线好友列表。
任务队列。(秒杀、抢购、12306 等等)
应用排行榜。
网站访问统计。
数据过期处理(可以精确到毫秒)
分布式集群架构中的 session 分离。
4.redis 在 Linux 上的安装
安装 redis 编译的 c 环境,yum install gcc-c++
将 redis-2.6.16.tar.gz 上传到 Linux 系统中
解压到/usr/local 下 tar -xvf redis-2.6.16.tar.gz -C /usr/local
进入 redis-2.6.16 目录 使用 make 命令编译 redis
在 redis-2.6.16 目录中 使用 make PREFIX=/usr/local/redis install 命令安装 redis
到/usr/local/redis 中
拷贝 redis-2.6.16 中的 redis.conf 到安装目录 redis 中
启动 redis 在 bin 下执行命令 redis-server redis.conf
如需远程连接 redis,需配置 redis 端口 6379 在 linux 防火墙中开发
/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT
/etc/rc.d/init.d/iptables save
5.启动 redis
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817144552007-580166937.png)
1)启动后看到如上欢迎页面,但此窗口不能关闭,窗口关闭就认为 redis 也关闭了(类 似
Tomcat 通过 bin 下的 startup.bat 的方式)
解决方案:可以通过修改配置文件 配置 redis 后台启动,即服务器启动了但不会穿件控制
台窗口
将 redis.conf 文件中的 daemonize 从 false 修改成 true 表示后台启动
2)使用命令查看 6379 端口是否启动 ps -ef | grep redis
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817144724130-297108267.png)
6.Redis 的 key-value
1)redis 是一种高级的 key-value 的存储系统
2)其中的 key 是字符串类型,尽可能满足如下几点:
1>key 不要太长,最好不要操作 1024 个字节,这不仅会消耗内存还会降低查找效率
2>key 不要太短,如果太短会降低 key 的可读性3>在项目中,key 最好有一个统一的命名规范(根据企业的需求)
4>其中 value 支持五种数据类型:
字符串型 string
字符串列表 lists
字符串集合 sets
有序字符串集合 sorted sets
哈希类型 hashs(map)
我们对 Redis 的学习,主要是对数据的存储,下面将来学习各种 Redis 的数据类型的 存储操做:
7.存储字符串 string
字符串类型是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,这便意味
着该类型可以接受任何格式的数据,如 JPEG 图像数据或 Json 对象描述信息等。 Redis 中字
符串类型的 Value 最多可以容纳的数据长度是 512M
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817144902869-1723078217.png)
1)set key value:设定 key 持有指定的字符串 value,如果该 key 存在则进行覆盖操作。总是返
回”OK”
2)get key:获取 key 的 value。如果与该 key 关联的 value 不是 String 类型,redis 将返回
错误信息,因为 get 命令只能用于获取 String value;如果该 key 不存在,返 回 null。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817144929747-585417054.png)
3)getset key value:先获取该 key 的值,然后在设置该 key 的值。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817144948906-638629431.png)
4)incr key:将指定的 key 的 value 原子性的递增 1.如果该 key 不存在,其初始值为 0 , 在
incr 之后其值为 1。如果 value 的值不能转成整型,如 hello,该操作将执 行失败并返回相应
的错误信息。
5)decr key:将指定的 key 的 value 原子性的递减 1.如果该 key 不存在,其初始值 为 0,
在 incr 之后其值为-1。如果 value 的值不能转成整型,如 hello,该操作将执 行失败并返回
相应的错误信息。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145004449-827878165.png)
6)incrby key increment:将指定的 key 的 value 原子性增加 increment,如果该key 不 存
在,器初始值为 0,在 incrby 之后,该值为 increment。如果该值不能转成 整型,如 hello
则失败并返回错误信息
7)decrby key decrement:将指定的 key 的 value 原子性减少 decrement,如果该 key 不
存在,器初始值为 0,在 decrby 之后,该值为 decrement。如果该值不能 转成整型,如 hello
则失败并返回错误信息
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145027754-1646624131.png)
8)append key value:如果该 key 存在,则在原有的 value 后追加该值;如果该 key存在,
则重新创建一个 key/value
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145044032-1924806634.png)
8.存储 lists 类型
在 Redis 中,List 类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,
我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis 将为
该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据
库中删除。List 中可以包含的最大元素数量是 4294967295(2^32 -1)。Integer=2^31 -1,从
元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效
的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的
是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。相信对于有良好数据结
构基础的开发者而言,这一点并不难理解。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145106310-1727518739.png)
1)lpush key value1 value2...:在指定的 key 所关联的 list 的头部插入所有的 values,如果该
key 不存在,该命令在插入的之前创建一个与该 key 关联的空链表,之后再向该链表的头部插入
数据。插入成功,返回元素的个数。
2)rpush key value1、value2…:在该 list 的尾部添加元素
3)lrange key start end:获取链表中从 start 到 end 的元素的值,start、end 可为负数,若为
-1 则表示链表尾部的元素,-2 则表示倒数第二个,依次类推…
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145124779-200869326.png)
4)lpushx key value:仅当参数中指定的 key 存在时(如果与 key 管理的 list 中没有值时,则该
key 是不存在的,只能 push 一个元素)在指定的 key 所关联的 list 的头部插入 value。
5)rpushx key value:在该 list 的尾部添加元素
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145158102-1411787213.png)
6)lpop key:返回并弹出指定的 key 关联的链表中的第一个元素,即头部元素。
7)rpop key:从尾部弹出元素。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145229100-1835679865.png)
8)rpoplpush resource destination:将链表中的尾部元素弹出并添加到头部
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145245419-1331606667.png)
9)llen key:返回指定的 key 关联的链表中的元素的数量。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145305164-2078766901.png)
10)lset key index value(修改):设置链表中的 index 的脚标的元素值,0 代表链表的头元素,
-1 代表链表的尾元素。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145412740-85714157.png)
11)lrem key count value(删除):删除 count 个值为 value 的元素,如果 count 大于 0,从头向尾遍历并删除 count 个值为 value 的元素,如果 count 小于 0,则从尾向头遍历并删除。
如果 count 等于 0,则删除链表中所有等于 value 的元素。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145435875-221441092.png)
12)linsert key before|after pivot value:在 pivot 元素前或者后插入 value 这个 元素。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145452639-1576966883.png)
9.存储 sets 类型
在 Redis 中,我们可以将 Set 类型看作为没有排序的字符集合,和 List 类型一样,我们也可
以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操
作的时间是常量时间。Set 可包含的最大元素数是 4294967295。和 List 类型不同的是,Set 集
合中不允许出现重复的元素。和 List 类型相比,Set 类型在功能上还存在着一个非常重要的特性,
即在服务器端完成多个 Sets 之间的聚合计算操作,如 unions、intersections 和 differences。
由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络 IO 开销
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145525627-767000473.png)
1)sadd key value1、value2…:向 set 中添加数据,如果该 key 的值已有则不会重复添加
2)smembers key:获取 set 中所有的成员
3)scard key:获取 set 中成员的数量
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145544925-366145118.png)
4)sismember key member:判断参数中指定的成员是否在该 set 中,1 表示存在,0 表示
不存在或者该 key 本身就不存在
5)srem key member1、member2…:删除 set 中指定的成员
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145605143-168290707.png)
6)srandmember key:随机返回 set 中的一个成员
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145622719-2080882080.png)
7)sdiff key1 key2:返回 key1 与 key2 中相差的成员,而且与 key 的顺序有 关。
即返回差集。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145634379-2033930745.png)
8)sdiffstore destination key1 key2:将 key1、key2 相差的成员存储在
destination 上
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145646625-802385321.png)
9)sinter key[key1,key2…]:返回交集。
10)sinterstore destination key1 key2:将返回的交集存储在 destination 上
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145700682-1304478053.png)
11)sunion key1、key2:返回并集。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145713462-224534174.png)
12)sunionstore destination key1 key2:将返回的并集存储在 destination 上
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190817145726109-869755581.png)
10.存储 sortedset
Sorted-Sets 和 Sets 类型极为相似,它们都是字符串的集合,都不允许重复的成员出现在
一个 Set 中。它们之间的主要差别是 Sorted-Sets 中的每一个成员都会有一个分数(score)与之
关联,Redis 正是通过分数来为集合中的成员进行从小到大的排序。然而需要额外指出的是,尽
管 Sorted-Sets 中的成员必须是唯一的,但是分数(score)却是可以重复的。
在 Sorted-Set 中添加、删除或更新一个成员都是非常快速的操作,其时间复杂度为集合中
成员数量的对数。由于 Sorted-Sets 中的成员在集合中的位置是有序的,因此,即便是访问位
于集合中部的成员也仍然是非常高效的。事实上,Redis 所具有的这一 特征在很多其它类型的
数据库中是很难实现的,换句话说,在该点上要想达到和 Redis 同样的高效,在其它数据库中进
行建模是非常困难的。
例如:游戏排名、微博热点话题等使用场景。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082805264-1298406257.png)
1)zadd key score member score2 member2 … :将所有成员以及该成员的 分数存
放到 sorted-set 中
2)zcard key:获取集合中的成员数量
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082831176-1621567094.png)
3)zcount key min max:获取分数在[min,max]之间的成员
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082847566-1705108087.png)
4)zincrby key increment member:设置指定成员的增加的分数。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082859084-856089547.png)
5)zrange key start end [withscores]:获取集合中脚标为start-end的成员,[withscores]
参数表明返回的成员包含其分数。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082916397-885531483.png)
6)zrangebyscore key min max [withscores] [limit offset count]:返回分数在[min,max]
的成员并按照分数从低到高排序。[withscores]:显示分数;[limit offset count]:offset,表
明从脚标为 offset 的元素开始并返回 count 个成员。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818082936824-1247300969.png)
7) zrank key member:返回成员在集合中的位置。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083001027-1976983276.png)
8)zrem key member[member…]:移除集合中指定的成员,可以指定多个成员。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083015172-289795743.png)
9) zscore key member:返回指定成员的分数
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083028811-1120528082.png)
11.存储 hash(map)
Redis 中的 Hashes 类型可以看成具有 String Key 和 String Value 的 map 容器。所以该类
型非常适合于存储值对象的信息。如 Username、Password 和 Age 等。如果 Hash中包含很
少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个 Hash 可以存储 4294967295
个键值对。
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083103178-2047260338.png)
1)hset key field value:为指定的 key 设定 field/value 对(键值对)。
2)hgetall key:获取 key 中的所有 filed-vaule
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083122191-2019721317.png)
3)hget key field:返回指定的 key 中的 field 的值
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083137967-1176177484.png)
4)hmset key fields:设置 key 中的多个 filed/value
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083203885-329340990.png)
5)hmget key fileds:获取 key 中的多个 filed 的值
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083227707-2049682992.png)
6)hexists key field:判断指定的 key 中的 filed 是否存在(0 代表不存在 1 代表存在)
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083245980-1027280973.png)
7)hlen key:获取 key 所包含的 field 的数量
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083259857-1850845599.png)
8)hincrby key field increment:设置 key 中 filed 的值增加 increment,如:age
增加 20
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083316108-2124768202.png)
12.Keys 的通用操作
1)keys pattern 获取所有的与 pattern 匹配的 keys *代表任意 0 到多个字符,?代表任意一
个字符
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083344535-2056315760.png)
2)Del key1 key2 .... 删除指定的一个或多个 key
3)Exists key 判断 key 是否存在,1 代表存在,0 代表不存在
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083358400-866605460.png)
4)Rename key newkey 为当前的 key 重命名
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083416873-336813285.png)
5)Expire key 设置 Key 的过期时间 单位:秒
6)ttl key 获取指定 key 所剩的超时时间,如果没有设置超时返回-1 如果返回-2 标识超时不存
在
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083439144-1387959339.png)
7)Type key 获取指定 key 管理的 value 的类型 ,以字符串的方式返回,返回的字符串包含有
string,list,set,hash,zset,如果可以不存在返回 none
![](https://img2018.cnblogs.com/blog/1536927/201908/1536927-20190818083454087-1433497216.png)