Redis
参考B站狂神说视频写的笔记,喜欢的可以去B站搜索狂神说
菜鸟成长之路,不喜勿喷,想交流的评论一起交流
Nosql概述
单机MySql

更多的使用静态的HTML~服务器根本没有压力,单机Mysql完全够用
这个情况下:网站的瓶颈:
1.数据量如果太大,一个机器放不下了!
2.数据的索引 单表数据超过300万就要建立索引
(B+Tree),一个机器内存也存不下了
3.访问量(读写混合),一个服务器承受不了
只要出现其中之一,网站就必须要升级了
缓存
Memcached(缓存)+MySQL+垂直拆分(读写分离)

每次查询数据库会很麻烦,所以我们希望减轻数据压力
发展过程:优化数据结构和索引—>文件缓存(IO)---->Memcached
分库分表+水平拆分+MYSQL集群
每个集群存一部分数据
本质:数据库(读,写)
MyISAM:表锁(100万条数据 查一个数据锁一张表)
高并发下就会出现严重的问题
Innodb:行锁
慢慢就开始使用分库分表来解决写的压力!

到如今
MYSQL关系型数据库就不够用了!数据量很多,变化很快
图形 JSON
MYSQL有的使用它来存储比较大的文件,博客,图片。。。数据库表很大,效率低
有一种数据库用来专门处理这种数据
MYSQL压力就变小了
大数据的IO压力 下 表几乎没办法更大
如今的服务器架构

Nosql = Not Only SQL
泛指非关系型数据库,随着web2.0诞生,传统型的关系型数据库很难对付web2.0时代!尤其是超大规模的高并发场景
关系型数据库: 表格 行 列
NoSQL特点
1.方便扩展(数据之间没有关系,很好扩展)
2.大数据量高性能
Redis一秒可以写8万次,读取11万条数据
NoSQL的缓存记录集,是一种细粒度的缓存,性能比较高
3.数据类型多类型
不需要事先设计数据库!:随取随用
4.传统RDBMS和NOSQL区别
传统的RDBMS
-结构化组织
-SQL
-数据和关系都存在单独的表中
-操作 数据定义语言
-严格的一致性
-基础的事务操作
NoSQL
-不仅仅是数据
-没有固定的查询语言
-键值对存储,列存储,文档存储,图形数据库(社交关系)
-最终一致性
-CAP定理和BASE理论 (异地多活)
-高性能,高可用,高可扩
-。。。
大数据了解3V+3高

阿里巴巴演进分析
此处省略,有兴趣的可以去百度看看O
NoSql的四大分类
KV键值对
- 新浪:Redis
- 美团:Redis+Tair
- 阿里、百度:Redis+Memecache
文档型数据库bson格式(和json一样)
MongoDB
是一个基于分布式文件存储的数据库,C++编写,主要处理大量的文档
MongoDB是一个介于关系型数据库与非关系型数据库的中间产品,MongoDB是非关系型数据库中功能最丰富功能最像关系型数据库的!!
ConthDB
列存储数据库
- HBase(大数据)
- 分布式文件系统
图形关系数据库
- 存储关系的拓扑图,朋友圈社交网络之间的关系,广告推荐。。。。
- Neo4j,InfoGrid
Redis入门
概述
Redis是什么
远程字典服务,支持网络,C语言编写,KV数据库
Redis能做什么
1.内存存储、持久化(内存是断电即失rdb、aof)
2.效率高,可用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器、计数器(浏览量!)
6……
特性
1.多样的数据类型
2.持久化
3.集群
4.支持事务
……
Linux安装redis
1.下载安装包
2.解压Redis的安装包
[root@bogon opt]# tar -zxvf redis-6.0.9.tar.gz

3.进入Redis
[root@bogon opt]# cd redis-6.0.9/

4.基本的环境安装
[root@bogon redis-6.0.9]# yum install gcc-c++
make
我以前已经安装过了,这里就省略了
镜像安装
教程网络很多跟着做就行
docker start redis#这个地方名字些什么我们启动的时候些什么
连接客户端语句
docker exec -it myredis redis-cli
关闭myredis服务
docker stop redis
查看当前涉及到redis的进程
[root@bogon docker]# ps -ef|grep redis
工具使用
redis-benchmark压力测试工具
| 序号 | 选项 | 描述 | 默认值 |
|---|---|---|---|
| 1 | -h | 指定服务器主机名 | 127.0.0.1 |
| 2 | -p | 指定服务器端口 | 6379 |
| 3 | -s | 指定服务器 socket | |
| 4 | -c | 指定并发连接数 | 50 |
| 5 | -n | 指定请求数 | 10000 |
| 6 | -d | 以字节的形式指定 SET/GET 值的数据大小 | 2 |
| 7 | -k | 1=keep alive 0=reconnect | 1 |
| 8 | -r | SET/GET/INCR 使用随机 key, SADD 使用随机值 | |
| 9 | -P | 通过管道传输 请求 | 1 |
| 10 | -q | 强制退出 redis。仅显示 query/sec 值 | |
| 11 | –csv | 以 CSV 格式输出 | |
| 12 | -l | 生成循环,永久执行测试 | |
| 13 | -t | 仅运行以逗号分隔的测试命令列表。 | |
| 14 | -I | Idle 模式。仅打开 N 个 idle 连接并等待。 |
我们简单测试一下
#测试是否连接正常
[root@bogon docker]# docker exec -it myredis redis-cli
127.0.0.1:6379> ping
PONG
#测试100个并发连接 100000请求
docker exec -it myredis redis-benchmark -h localhost -p 6379 -c 100 -n 100000
分析
====== SET ======
100000 requests completed in 3.56 seconds #10万个请求3.56s
100 parallel clients #100个并发客户端
3 bytes payload #每次写入3个字节
keep alive: 1 #只有一台服务器来处理这些请求,单机性能
host configuration "save":
host configuration "appendonly": yes
multi-thread: no
6.49% <= 1 milliseconds #第一毫秒处理了
44.88% <= 2 milliseconds
80.50% <= 3 milliseconds
93.31% <= 4 milliseconds
98.07% <= 5 milliseconds
99.48% <= 6 milliseconds
99.73% <= 7 milliseconds
99.80% <= 8 milliseconds
99.85% <= 9 milliseconds
99.88% <= 10 milliseconds
99.90% <= 11 milliseconds
99.90% <= 12 milliseconds
99.92% <= 15 milliseconds
99.92% <= 16 milliseconds
99.94% <= 17 milliseconds
99.98% <= 18 milliseconds
100.00% <= 18 milliseconds
28074.12 requests per second #每秒处理多少请求
基础的知识
redis默认的有16个数据库
默认使用的是第0个数据库
可以使用select切换数据库
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> DBSIZE #查看数据库大小
(integer) 0
127.0.0.1:6379[3]> set name wangqinghua
OK
127.0.0.1:6379[3]> DBSIZE #只针对于3号数据库,其他数据库没有
(integer) 1
查看当前数据库所有的key
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> get name
"wangqinghua"
清除当前的数据库
127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)
清除全部数据库的内容
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> flushall
OK
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> keys * #本来我们测试性能的时候插入了,但是在3 数据库执行了flushall清空了全部
(empty array)
Redis是单线程的!
Redis是基于内存操作的,CPU不是Redis的瓶颈,Redis的瓶颈是根据机器的内存和网络的带宽,既然可以使用单线程来做,就使用了单线程!
Redis是C语言写的,官方提供的是100000+的QPS,完全不比同样是使用KV的Memecache差
Redis单线程怎么还这么快?
误区1.高性能的服务器一定是多线程的么?
误区2.多线程(CPU上下文切换)一定比单线程效率高么?
核心 :
redis是将所有的数据全部放在内存中的,所以说使用单线程效率最高(如果是多线程,需要上下文切换),对于内存系统来说,没有上下文切换就是效率最高的,多次读写在一个CPU上,在内存系统看来,单线程的Redis就是最佳方案
五大数据类型
官网文档
Redis是一种开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。它支持数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超日志,带有半径查询和流的地理空间索引。Redis具有内置的复制,Lua脚本,LRU驱逐,事务和不同级别的磁盘持久性,并通过Redis Sentine(哨兵模式)l和Redis Cluster自动分区提供高可用性。
Redis-Key
什么是Redis-Key
判断键值是否存在
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name wanghua
OK
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> key *
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name #存在这个键值么
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 1 #移除这个 1代表当前库
(integer) 1
127.0.0.1:6379> keys *
1) "age"
设置key的过期时间(单位是S)
我们可以联想到我们的单点登录
127.0.0.1:6379> set name wang
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> get name
"wang"
127.0.0.1:6379> expire name 10 #设置我们这个键值对的过期时间
(integer) 1
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> ttl name #查看当前key的剩余时间
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 0
127.0.0.1:6379> get name #已经没了
(nil)
查看key的类型(type)
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name wang
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> type name
string
127.0.0.1:6379> type age
string
String(字符串)
127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> keys * #获得所有key
1) "key1"
127.0.0.1:6379> exists key1 #是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" #像一个key中追加字符串
(integer) 7
127.0.0.1:6379> get key1 #追加成功
"v1hello"
127.0.0.1:6379> STRLEN key1 #获取字符串长度
(integer) 7
127.0.0.1:6379> APPEND key1 "wanghuahua"
(integer) 17
127.0.0.1:6379> STRLEN key1
(integer) 17
127.0.0.1:6379> get key1
"v1hellowanghuahua"
127.0.0.1:6379> keys *
1) "key1"
#给一个不存在的key追加值会怎么样呢?
127.0.0.1:6379> APPEND name "wangtaotao"
(integer) 10 #返回长度
#实验发现给一个不存在的key追加值会创建出来一个key
127.0.0.1:6379> keys *
1) "name"
2) "key1"
127.0.0.1:6379> get name
"wangtaotao"
127.0.0.1:6379>
#######################################################
#Redis中自增自减操作(我们的浏览量怎么做)
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自减1
(integer) 1
127.0.0.1:6379> get views
"1"
####怎么设置步长呢?
127.0.0.1:6379> incrby views 10 #设置增长量
(integer) 11
127.0.0.1:6379> incrby views 10
(integer) 21
127.0.0.1:6379> get views
"21"
127.0.0.1:6379> decrby views 10 #设置自减量
(integer) 11
127.0.0.1:6379> get views
"11"
#######################################################
字符串范围
#######################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello,wangtaotao"
OK
127.0.0.1:6379> get key1
"hello,wangtaotao"
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串[0,3]的内容
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1 #相当于获取全部了setget
"hello,wangtaotao"
####替换
127.0.0.1:6379> keys *
1) "key1"
2) "key2"
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 1 xx #指定我们的下标1替换为
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
#######################################################
#setex (set with expire) #设置过期时间
#setnx (set if not expire) #不存在在设置(在分布式锁中会常常使用)
127.0.0.1:6379> clear
127.0.0.1:6379> setex key3 30 "hello" #设置了一个key3有过期时 间,30s过期
OK
127.0.0.1:6379> ttl key3 #查看该key过期时间
(integer) 25
127.0.0.1:6379> ttl key3
(integer) 22
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx myvalue "redis" #如果myvalue不存在,则 myvalue创建
(integer) 1
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> setnx myvalue "MongoDB" #如果myvalue存在,则创 建失败
(integer) 0 #返回0 说明我们没有修改成功
127.0.0.1:6379> get myvalue
"redis"
批量获取/设置
#######################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #存在不创建,不存在创建?
(integer) 0 #返回0==>原子性操作,要么全成功,要么全失败
127.0.0.1:6379> get k4
(nil)
#######################################################
对象
#######################################################
#设置user对象
#这里的key的设计是:
user:{id}:{filed}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
#######################################################
组合命令
############################################################
#先get在set getset
#如果不存在则返回null,再去赋值
#存在的话,先返回原来的值,再去赋成新的值
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db MongoDB
"redis"
127.0.0.1:6379> get db
"MongoDB"
############################################################
String的类似使用场景:
- 计数器
- 统计浏览量
- 粉丝数
- 对象缓存存储
List
基本数据类型:列表
在Redis里面,List可以当做栈、队列、阻塞队列等等
所有的List命令都是以L开头
添加数据
############################################################
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> LPUSH list one #将一个或多个插入列表头部
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> LRANGE list 0 1 #后面的先拿出来
1) "three"
2) "two"
#从右边插入,插到了最后边的位置
127.0.0.1:6379> RPUSH list right
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
############################################################
移出数据POP
############################################################
LPOP RPOP
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
######移出list第一个元素
127.0.0.1:6379> LPOP list
"three"
#####移出list最后一个元素
127.0.0.1:6379> RPOP list
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
############################################################
LINDEX
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> LINDEX list 1 #通过下标获得list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"two"
############################################################
其他操作
############################################################
#######获取list长度
127.0.0.1:6379> LPUSH list one
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list threre
(integer) 3
127.0.0.1:6379> LLEN list
(integer) 3
#####移除指定的值
#取关 踢出粉丝
127.0.0.1:6379> LPUSH list threre
(integer) 4
127.0.0.1:6379> LREM list 1 one #移出多少个指定的数据 精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "threre"
2) "threre"
3) "two"
127.0.0.1:6379> LREM list 1 threre #我们先移出一个
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "threre"
2) "two"
127.0.0.1:6379> LPUSH list threre
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "threre"
2) "threre"
3) "two"
127.0.0.1:6379> LREM list 2 threre #添加后一次性移出两个
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
############################################################
########只获取/保留一部分
##Java中有trim去空格 修剪list:截断
127.0.0.1:6379> RPUSH mylist hello
(integer) 1
127.0.0.1:6379> RPUSH mylist hello1
(integer) 2
127.0.0.1:6379> RPUSH mylist hello2
(integer) 3
127.0.0.1:6379> RPUSH mylist hello3
(integer) 4
###通过下标截取指定的长度 list被修改了原地操作,只剩下了截取的元素
127.0.0.1:6379> LTRIM mylist 1 2
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello1"
2) "hello2"
############################################################
## rpoplpush 移除列表最后一个元素并添加到新的列表
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "hello1"
(integer) 2
127.0.0.1:6379> RPUSH mylist "hello2"
(integer) 3
#移除列表最后一个元素并添加到目标的列表 目标列表不存在则自动创建
127.0.0.1:6379> RPOPLPUSH mylist myotherlist
"hello2"
127.0.0.1:6379> LRANGE mylist 0 -1 #查看原来列表
1) "hello"
2) "hello1"
127.0.0.1:6379> LRANGE myotherlist 0 -1 #查看目标列表
1) "hello2"
############################################################
## lset将列表指定下标的值替换成另一个值,相当于更新
## 如果不存在该列表或下标则会报错,存在才会修改
127.0.0.1:6379> exists list
(integer) 0
127.0.0.1:6379> lset list 0 item #列表吧不存在能set值么
(error) ERR no such key #报错不能
127.0.0.1:6379> LPUSH list value1
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1 #我们创建了这个列表
1) "value1"
127.0.0.1:6379> lset list 0 item #我们现在有值能这样set么
OK
127.0.0.1:6379> LRANGE list 0 -1 #可以set,相当于修改
1) "item"
127.0.0.1:6379> lset list 1 other #列表中不存在的下标能set么
(error) ERR index out of range #不能够set
############################################################
## linsert将某个具体的值插入的列表指定元素前面或者后面
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "world"
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" "other" #在 其前面插入
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LINSERT mylist after "world" "hhh" #在 其后面插入
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "hhh"
############################################################
小结
实际上是一个链表,有before Node after,left,right 都可以插入
- 如果key不存在,创建新链表
- 如果key存在,新增内容
- 如果移除了所有的值,空链表也代表不存在
- 在两边插入或者改动,效率最高!!!中间元素,相对效率低一点
消息排队!!:LPUSH RPOP 左边进,右边出 队列
LPUSH LPOP 左边进,左边出 栈
Set(集合类型)
**特点:**set中的值是不能重复的
set中的值是无序的
set集合操作基本上以S开头
添加取出
############################################################
## sadd添加元素
## smembers 查看set集合
## Java中有contans SISMEMBER查看set中是否包含指定值
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "taotao"
(integer) 1
127.0.0.1:6379> sadd myset "love taotao"
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "love taotao"
2) "hello"
3) "taotao"
#判断有没有指定的元素
127.0.0.1:6379> SISMEMBER myset hello #不加""也可以
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0
############################################################
## SCARD获取set集合中元素的个数
127.0.0.1:6379> SCARD myset
(integer) 3
127.0.0.1:6379> sadd myset "taotao22222"
(integer) 1
127.0.0.1:6379> SCARD myset
(integer) 4
#### SREM移除set中的指定元素
127.0.0.1:6379> SREM myset hello
(integer) 1
127.0.0.1:6379> scard myset
(integer) 3
127.0.0.1:6379> SMEMBERS myset
1) "taotao22222"
2) "love taotao"
3) "taotao"
#### set无序不重复集合抽取随机
#### SRANDMEMBER随机抽取指定个数元素
127.0.0.1:6379> SMEMBERS myset
1) "taotao22222"
2) "love taotao"
3) "taotao"
127.0.0.1:6379> SRANDMEMBER myset
"love taotao"
127.0.0.1:6379> SRANDMEMBER myset
"taotao22222"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "taotao22222"
2) "taotao"
############################################################
# SPOP随机删除set中的元素
127.0.0.1:6379> SPOP myset
"taotao22222"
127.0.0.1:6379> SMEMBERS myset
1) "love taotao"
2) "taotao"
127.0.0.1:6379> SPOP myset
"taotao"
127.0.0.1:6379> SMEMBERS myset
1) "love taotao"
############################################################
## SMOVE 将一个指定的值移动到另外一个set中
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "world"
(integer) 1
127.0.0.1:6379> sadd myset "taotao"
(integer) 1
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> keys *
1) "myset2"
2) "myset"
#将"taotao"这个元素从myset移动到myset2中
127.0.0.1:6379> SMOVE myset myset2 "taotao"
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "world"
127.0.0.1:6379> SMEMBERS myset2
1) "set2"
2) "taotao"
############################################################
## 微博、B站 共同关注!!(并集)
#数字集合类
# --差集 SDIFF返回前者不同于后者的元素
# --交集 SINTER返回两者相同的元素 共同好友的实现
# --并集 SUNION返回两者合在一起的元素
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2
1) "b"
2) "a"
127.0.0.1:6379> SINTER key1 key2
1) "c"
127.0.0.1:6379> SUNION key1 key2
1) "d"
2) "a"
3) "c"
4) "b"
5) "e"
############################################################
微博
A用户将所有关注的人放在一个集合中!将他的粉丝也放到一个集合中
B用户将所有关注的人放在一个集合中!将他的粉丝也放到一个集合中
共同专注,爱好,粉丝A,B两个集合做SINTER交集计算就出来了
二度好友(六度分割理论)
Hash(哈希)
Map集合,key-map====key-<key,value>
本质上和String没有太大区别,还是简单的key-value
set myhash field taotao
hash操作基本以h开头
存取值
############################################################
## hset单个赋值
## hget单个取出
## hmset多个赋值,存在的覆盖掉,不存在创建
## hmget取出多个hash值
## HGETALL 取出全部hash值
# key value
127.0.0.1:6379> hset myhash field1 taotao
(integer) 1
127.0.0.1:6379> hget myhash field1
"taotao"
####我们的field1存在,理论上是要被覆盖的
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
############################################################
### hdel删除指定的key字段,对应的value值也就消失了
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
############################################################
## hlen获取hash表的字段数量
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> HLEN myhash
(integer) 2
############################################################
### HEXISTS判断hash中指定字段存不存在
127.0.0.1:6379> HEXISTS myhash field1
(integer) 1
127.0.0.1:6379> HEXISTS myhash field3
(integer) 0
############################################################
### HKEYS 只获得我们的field字段
### HVALS 只获得我们的value
127.0.0.1:6379> HKEYS myhash
1) "field2"
2) "field1"
127.0.0.1:6379> HVALS myhash
1) "world"
2) "hello"
############################################################
## HINCRBY 自增 -1相当于自减
## hsetnx 不存在则设置,如果存在则不设置
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1
(integer) 6
127.0.0.1:6379> HINCRBY myhash field3 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hello
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 world
(integer) 0
############################################################
应用
hash存储变更的数据:user name age,hash更适合存储用户,String更加适合字符串存储
127.0.0.1:6379> hset user:1 name wangtaotao
(integer) 1
127.0.0.1:6379> hget user:1 name
"wangtaotao"
127.0.0.1:6379> hset user:1 age 18
(integer) 1
127.0.0.1:6379> hget user:1 age
"18"
127.0.0.1:6379> HGETALL user:1
1) "name"
2) "wangtaotao"
3) "age"
4) "18"
Zset(有序集合)
在set的基础上,增加了一个值
set:set k1 v1
zset:zset k1 score1 v1
方法
############################################################
### zadd 增加一个zset元素 可以添加多个值
### ZRANGE 查看zset指定范围元素
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 there
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1
1) "one"
2) "two"
3) "there"
############################################################
## 添加三个用户的薪水
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 5000 zahngsan
(integer) 1
127.0.0.1:6379> zadd salary 100000 taotao
(integer) 1
### 从小到大
#### ZRANGEBYSCORE 排序 包括-无穷到正无穷
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
1) "xiaohong"
2) "zahngsan"
3) "taotao"
#### ZRANGEBYSCORE 从大到小排序
127.0.0.1:6379> ZREVRANGE salary 0 -1
1) "taotao"
2) "zahngsan"
#### ZRANGEBYSCORE 排序 包括-无穷到正无穷 带上sources数据
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores
1) "xiaohong"
2) "2500"
3) "zahngsan"
4) "5000"
5) "taotao"
6) "100000"
#### ZRANGEBYSCORE 指定限制范围查询出来 带sources数据
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores
1) "xiaohong"
2) "2500"
############################################################
### ZRANGE 移除元素
### ZCARD 获取有序集合中的个数
127.0.0.1:6379> ZRANGE salary 0 -1
1) "xiaohong"
2) "zahngsan"
3) "taotao"
127.0.0.1:6379> ZREM salary xiaohong
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "zahngsan"
2) "taotao"
127.0.0.1:6379> ZCARD salary
(integer) 2
############################################################
#### ZCOUNT 获取指定区间Zset的成员数量
flushdb
127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 2 world 3 taotao
(integer) 2
127.0.0.1:6379> ZCOUNT myset 1 3
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 2
(integer) 2
############################################################
案例思路:set的排序版
存储班级成绩,员工工资表!
带权重执行 普通消息!重要消息!加权操作!!1
排行榜应用场景 取TOP10功能