学习资料:
【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩_bilibili
(72条消息) Redis(基于狂神说Java-Redis)_你给我把被子盖好了,别再踢了的博客-CSDN博客_狂神说redis
学习目的
Redis等关系型数据库作缓存去缓存使用频率高的数据,减轻Mysql等关系型数据库的压力
1、NoSQL简介
1.1 什么是NoSQL
NoSQL翻译为Not Only SQL,译为不仅仅是SQL,意指非关系型数据库
web2.0的诞生,传统的关系型数据库已经很难对付web2.0时代!特别是指大规模高并发社区!会出现很多问题,NoSQL在大数据时代发展的十分迅速,尤其是Redis
很多的数据类型用户的个人信息,社交网络,地理位置,这些数据类型的存储不需要一个固定的格式,不需要太多操作就可以实现横向拓展,就比如Redis,它是使用类似于Java的Map<String, Object>来实现存储,键值对的形式存储,这只是NoSQL的解决方式之一
1.2 NoSQL 特点
1、方便扩展(数据之间没有联系可以快速拓展)
2、大数据量高性能,Redis可以支持8w的并发量(写操作),11w访问量(读操作),NoSQL的缓存记录级,是一种细粒度的缓存,性能比较高
3、数据类型多样性(不需要事先设计数据库,随取随用,数据量过大就无法设计)
4、传统的关系数据库管理系统(Relational Database Management System:RDBMS)和NoSQL的区别
关系型数据库与非关系型数据库对比
传统的RDBMS(关系型数据库)
- 结构化
- SQL
- 数据和关系存在于单独的表中 row(行) column(列)
- 数据操作,数据定义语言
- 严格的一致性
- 基础的事务
NoSQL(非关系型数据库)
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库
- 最终一致性
- CAP定律和BASE理论
5、大数据时代的3V + 3高
-
大数据时代的3V
- 海量Volume
- 多样Variety
- 实时Velocity
- 大数据时代的3高
-
高并发
- 高可用(随时水平拆分,机器不够了,随时扩展)
- 高性能(保证用户体验和性能)
- 真正在公司中用到的实践,NoSQL + 关系型数据库,这是最强组合,也是阿里巴巴的架构演进
实际 NoSql+关系型数据库 一起使用
# 商品的基本信息
名称、价格、商家信息
MySQL / Oracle 去IOE化(IOE:IBM、Oracle、EMC存储设备)
# 商品描述
评论,文本信息多
文档型数据库,MongoDB
# 图片
分布式文件系统 FastDFS
淘宝:TFS
Google:GFS
Hadoop:HDFS
阿里云:OSS
# 商品关键字(搜索)
搜索引擎 solr elasticsearch
淘宝:ISearch,ISearch作者,阿里的多隆
# 商品热门波段信息
内存数据库
Redis Tair Memcached...
# 商品交易,外部支付接口
第三方应用
1.3 NoSQL的四大分类
1、KV键值对
- 新浪:Redis
- 美团:Redis + Tair
- 阿里,百度:Redis + Memcached
2、文档型数据库(Bson,Binary Json,二进制Json)
-
MongoDB,需要掌握,它是一种基于分布式文件存储的数据库,由C++编写,主要用来处理大量的文档
-
MongoDB 是一种介于关系型数据库和非关系型数据库之间的一种中间产品,功能丰富,而且MongoDB是NoSQL中最像关系型数据库的产品
-
ConthDB
3、列存储数据库
- HBASE
- 分布式文件系统
4、图形关系数据库
- 它不是存图片的!它存放的是关系,就好比一个人的社交圈,可以动态扩充
- Neo4j,InfoGrid
4种分类的对比
2、Redis入门
本次使用的Redis的版本采用的是5.0.10
2.1 Redis简介
什么是Redis?
Redis(Remote Directory Server),中文译为远程字典服务,免费开源,由C语言编写,支持网络,可基于内存也可持久化的日志型,KV键值对数据库,并且提供多种语言的API,是当下NoSQL中最热门的技术之一!被人们称之为结构化数据库!
Redis能干嘛?
- 内存存储,持久化,因为内存断电即失,并且Redis支持两种持久化方式,RDB / AOF
- 效率高,可用于高速缓存
- 消息发布订阅(消息队列)
- 地图信息分析
- 计数器(eg:微博浏览量)
…
特性
-
数据类型多样
-
持久化
-
Redis集群
-
事务
…
官网:https://redis.io/
Redis中文文档:http://www.redis.cn/documentation.html
下载地址:进入官网下载即可(Windows版本需要在GitHub上下载,并且Redis版本已停更较长时间,不建议使用)
并且,Redis官方推荐在Linux服务器上进行搭建
2.2 windows 安装 Radis
D:\tool\Redis-x64-5.0.14
文件 | 作用 |
---|---|
redis-benchmark.exe | 测试性能 |
redis-check-aof.exe | 检查AOF持久化 (Redis支持两种持久化方式,RDB / AOF) |
redis-server.exe | 启动服务 |
redis-cli.exe | 客户端 |
1、运行服务
双击redis-server.exe 启动Redis服务 或 打开一个 cmd 窗口 使用 cd 命令切换目录运行:
redis-server.exe redis.windows.conf
这时候另启一个 cmd 窗口,原来的不要关闭,不然就无法访问服务端了。
2、连接Redis
使用 Redis客户端(redis-cli.exe)连接Redis服务
切换到 redis 目录下运行:
redis-cli.exe -h 127.0.0.1 -p 6379
或
redis-cli
3、连接成功
D:\tool\Redis-x64-5.0.14
λ redis-cli.exe
127.0.0.1:6379>
4、使用
127.0.0.1:6379> ping #测试连接
PONG
127.0.0.1:6379> set name zs
OK
127.0.0.1:6379> get name
"zs"
127.0.0.1:6379>
2.3 Linux安装Redis
安装Redis的第一种,官网下载安装包
1、下载安装包,redis-5.0.10.tar.gz
2、下载到Windows之后,用Xftp工具上传至Linux
3、解压安装包并将其解压
tar -zxvf redis-5.0.4.tar.gz
并且解压之后可以看见Redis的配置文件redis.conf
4、同时还需要基本的环境搭建
# 保证Redis的正常运行,gcc的安装也是必要的
yum install gcc-c++
# 查看版本
g++ -v
# 安装Redis所需要的环境
make
# 此命令只是为了确认当前所有环境全部安装完毕,可以选择不执行
make install
Redis的安装,默认在/usr/local/bin
下
5、之后,需要将Redis的配置文件复制到bin目录下,可以提前准备好一个目录,然后在复制到新创建好的目录中
[root@192 opt]# cd /opt/redis-5.0.4/
[root@192 redis-5.0.4]# ls
00-RELEASENOTES CONTRIBUTING deps Makefile README.md runtest runtest-sentinel src utils
BUGS COPYING INSTALL MANIFESTO redis.conf runtest-cluster sentinel.conf tests
[root@192 redis-5.0.4]# cp redis.conf /usr/local/bin/myconfig/
[root@192 redis-5.0.4]#
6、然后修改复制之后的配置文件,修改一条信息,修改的信息就是图中划红线的位置,它的意思是指守护进程模式启动,即可以在后台运行Redis
vim 搜索 方法:/str
daemonize
7、随后就可以开始启动Redis服务(通过指定的配置文件启动服务)
[root@192 bin]# cd /usr/local/bin
[root@192 bin]# redis-server /usr/local/bin/myconfig/redis.conf
8、连接
/usr/local/bin/
[root@192 bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> get age
"23"
127.0.0.1:6379> keys *
1) "age"
9 、查看进程运行
[root@192 ~]# ps -ef|grep redis
root 2057 1967 0 16:21 pts/0 00:00:00 grep --color=auto redis
[root@192 bin]# redis-server /usr/local/bin/myconfig/redis.conf # 启动Redis服务
#...
[root@192 bin]# ps -ef|grep redis
root 2063 1 1 16:25 ? 00:00:00 redis-server 127.0.0.1:6379
root 2069 1967 0 16:25 pts/0 00:00:00 grep --color=auto redis
[root@192 bin]#
10、关闭服务
127.0.0.1:6379> shutdown
127.0.0.1:6379> shutdown
not connected> exit
[root@192 bin]# ps -ef|grep redis
root 2074 1967 0 16:29 pts/0 00:00:00 grep --color=auto redis
2.4 避免中文乱码
有时候会有中文乱码。
要在 redis-cli 后面加上 --raw
redis-cli --raw
就可以避免中文乱码了
[root@192 bin]# redis-cli --raw
127.0.0.1:6379> set name 张三
OK
127.0.0.1:6379> get name
张三
2.5 性能测试工具
redis-benchmark性能测试工具
- 测试命令
# 当前命令表示,性能测试,在本机,端口号6379,并发连接数100,每个连接10w个请求数量
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
- 测试结果
[root@192 bin]# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
# 测试结果如下,以Redis的INLINE命令为例
====== PING_INLINE ======
100000 requests completed in 5.24 seconds # 十万个请求在5.24秒之内被处理
100 parallel clients # 每次请求都有100个客户端在执行
3 bytes payload # 一次处理3个字节的数据
keep alive: 1 # 每次都保持一个服务器的连接,只用一台服务器处理这些请求
0.37% <= 1 milliseconds
13.17% <= 2 milliseconds
# ...
100.00% <= 104 milliseconds # 所有的请求在104秒之内完成
19076.69 requests per second # 平均每秒处理19076.69个请求
====== PING_BULK ====== # set、get、ping等每个命令都会测试
100000 requests completed in 4.45 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.31% <= 1 milliseconds
# ...
2.6 Redis基础知识
备注:在Redis中,关键字语法不区分大小写!
Redis有16个数据库支持,为啥嘞,可以查看redis.conf配置文件
并且初始数据库默认使用0号数据库(16个数据库对应索引0到15)
- 可以使用select命令切换数据库:select n(0-15)
127.0.0.1:6379> select 12
OK
127.0.0.1:6379[12]> select 0
OK
127.0.0.1:6379> dbsize # 查看当前库的key数量
(integer) 0
- 清空数据库信息
127.0.0.1:6379> keys *
1) "myset:__rand_int__"
2) "mylist"
3) "key:__rand_int__"
4) "name"
5) "counter:__rand_int__"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379>
# 还有一个清空的命令,叫做flushall,它的意思是清空16个数据库中的全部信息。
# 不管在那种数据库中,清空库一直都是需要慎重操作的
题外话:为什么Redis选用6379作为默认端口号?
6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。MERZ长期以来被Redis作者antirez及其朋友当作愚蠢的代名词。后来Redis作者在开发Redis时就选用了这个端口。(摘自知乎)
Redis是单线程的(从Redis6.0.1开始支持多线程)
Redis的读写速度很快,官方表示,Redis基于内存操作,CPU不是Redis的性能瓶颈,Redis的性能瓶颈是根据机器的内存和带宽
Redis是C语言编写,官方提供的数据为10万+的QPS(Queries-Per-Second,每秒内的查询次数)
Redis单线程为什么速度还是这么快?
对于Redis,有两个误区:
1、高性能的服务器一定是多线程的?
2、多线程一定比单线程效率高?
Redis将所有的数据全部放在内存中,使用单线程去操作效率比较高,对于多线程,CPU有一种东西叫做上下文切换,这种操作耗时,对于内存系统来说,没有上下文切换,效率一定是最高的。
Redis使用单进程的模式来处理客户端的请求,对大部分事件的响应都是通过epoll函数的加强封装,Redis的实际处理速度依靠主进程的执行效率,epoll可以显著提高程序在大量并发连接中系统的CPU利用率
Redis中文网翻译:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
3、基础语法
基础语法(命令小写) | 作用 |
---|---|
set key value | 设置一个key |
get key | 获取一个key对应value |
exists key | 查询key是否存在 |
move key n(n是数字) | 将当前key移动到指定的几号数据库中 |
keys * | 查询当前数据库中全部的key |
expire key time | 设置当前key的过期时间 |
ttl key | 查询当前key的存活时间 |
type key | 查看key的数据类型 |
flushdb | 清空当前数据库信息(慎用) |
flushall | 空16个数据库中的全部信息(慎用) |
select n | 选择数据库 |
基础语法(命令大写):
SET key value 设置一个key
GET key 获取一个key对应value
EXISTS key 查询key是否存在
MOVE key n(数字) 将当前key移动到指定的几号数据库中
KEYS * 查询当前数据库中全部的key
EXPIRE key time 设置当前key的过期时间
TTL key 查询当前key的存活时间
TYPE key 查看key的数据类型
1、set key value
127.0.0.1:6379> set name 张三 # 设置key-value
OK
127.0.0.1:6379> get name # 查询key指定的value
张三
2、exists key
127.0.0.1:6379> exists name # 查看当前key是否存在
1
127.0.0.1:6379> exists name1
0
3、move
127.0.0.1:6379> move name 1
1
127.0.0.1:6379> KEYS *
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
name
4、expire key time
127.0.0.1:6379[1]> expire name 5 # 设置当前key的过期时间,单位是秒
1
127.0.0.1:6379[1]> ttl name # 查看指定key的存活时间,
-2 # 返回-2表示当前key已经过期,如果为-1,表示永不过期
127.0.0.1:6379> KEYS * # name 过期被清空
(empty list or set)
5、type key
127.0.0.1:6379[1]> set name 张三
OK
127.0.0.1:6379[1]> type name
string
4、Redis五大数据类型
以下命令记忆小写(命令提示大写),一是好记,二是java中与redis相关的方法与小写命令类似
4.1 String(字符串)
语法 | 作用 |
---|---|
append key Value | 对指定key实现字符串拼接,如果key不存在,等同于set |
strlen key | 查看指定key的长度 |
incr key | 对指定key进行自增,类似于Java中的i++ |
decr key | 自减,类似于Java的i– |
incrby key n | 对指定key按照指定的步长值进行自增 |
decrby key n | 按照指定的步长值自减 |
setrange key index value | 从指定key的索引开始,插入指定的value值。 |
getrange key index value | 将指定key按照索引的开始和结束范围进行截取,成为一个新的key |
setex key time value | 设置一个有存活时间的key |
setex key value | 如果这个key不存在,即创建 |
mset key value … | 设置多个key value |
mget key value | 获取多个key指定的value |
getset key value | 先获取指定的key,然后再设置指定的value |
# 语法:
APPEND key appendValue # 对指定key实现字符串拼接,如果key不存在,等同于set
STRLEN key # 查看指定key的长度
INCR key # 对指定key进行自增,类似于Java中的i++
DECR key # 自减,类似于Java的i--
INCRBY key n # 对指定key按照指定的步长值进行自增
DECRBY key n # 按照指定的步长值自减
SETRANGE key index value # 从指定key的索引开始,插入指定的value值。如果key不存 在且索引>1,那么当前的索引之前的数据,会用\x00代替并占用一个索引位置,相当于ASCII码中的null
GETRANGE key startIndex endInde #将指定key按照索引的开始和结束范围进行截取,成为一个新的key
SETEX key time value # 设置一个有存活时间的key
SETNX key value # 如果这个key不存在,即创建
MSET key value ... #设置多个key value
MGET key ... #获取多个key指定的value
GETSET key value # 先获取指定的key,然后再设置指定的value
1、简单使用
127.0.0.1:6379[1]> set name ab
OK
127.0.0.1:6379[1]> append ab cd
2
127.0.0.1:6379[1]> get name
ab
127.0.0.1:6379[1]> strlen name
2
2、实现自增自减效果
- 注意:value的自增和自减只适用于Integer类型
127.0.0.1:6379[1]> incr age
26
127.0.0.1:6379[1]> decr age
25
127.0.0.1:6379[1]> incrby age 10
35
127.0.0.1:6379[1]> decrby age 24
11
3、实现字符串截取效果
127.0.0.1:6379> set k1 hello,xiaohuang
OK
127.0.0.1:6379> get k1
"hello,xiaohuang"
127.0.0.1:6379> GETRANGE k1 0 3 # 实现字符串截取,有起始索引和结束索引,相当于Java中的subString()
"hell"
# 如果结束索引为-1,则表示当前截取的字符串为全部
127.0.0.1:6379> GETRANGE k1 0 -1
"hello,xiaohuang"
4、实现字符串的替换效果
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 2 hello # 实现字符串的替换效果,命令中的数字“2”表示从索引2的位置开始将其替换为指定字符串
(integer) 7
127.0.0.1:6379> get key2
"abhello"
5、设置过期时间
# setex(set with expire) # 设置过期时间
# setnx(set with not exist) # 如果key不存在,创建(分布式锁中常用)
127.0.0.1:6379[1]> setex name 10 张三
OK
127.0.0.1:6379[1]> keys *
name
127.0.0.1:6379[1]> get name
127.0.0.1:6379[1]> keys *
127.0.0.1:6379> setnx lan redis # 如果key不存在,即创建
(integer) 1
127.0.0.1:6379> setnx lan mongodb
(integer) 0 # 0表示没有设置成功,也可理解为“有0行受到影响”
127.0.0.1:6379> get lan
"redis"
6、一次性设置(获取)多个键值对
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> KEYS *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
# 也可以在这边的语法前面加上一个m,代表设置多个
127.0.0.1:6379> msetnx k1 vv1 k4 v4
(integer) 0
# 但是这边同时设置多个值,如果有一个key已经存在,那么这一条设置语句便不会执行成功,
# 因为Redis单条语句是原子操作,要么同时成功,要么同时失败
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
# 在Redis中,还推荐了一个比较有意思的东西
# 这是Redis中关于key的命名,可以用“:”来代表层次结构,可以对指定的key进行分类存储
127.0.0.1:6379> mset user:1:name xiaohuang user:1:age 21
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "xiaohuang"
2) "21"
127.0.0.1:6379> getset sqlan redis # 先获取当前key指定的value,如果不存在,会返回nil(null),然后设置新值
(nil)
127.0.0.1:6379> get sqlan
"redis"
127.0.0.1:6379> getset sqlan hbase
"redis"
127.0.0.1:6379> get sqlan
"hbase"
类似于Redis中String这样的使用场景,value值可以是字符串,也可以是其他类型
String的存储的字符串长度最大可以达到512M
主要用途
- 计数器
- 统计多单位的数量
- 一个用户的粉丝数
- 一个有过期时间的验证码
4.2 List(列表)
Redis中的List列表可以做很多事情,可以将其看成数据结构中的栈,也可以是队列,或者阻塞队列
命令 | 作用 | 关键字 |
---|---|---|
LPUSH key value1 value2 … | 设置一个key,从头部插入数据(头插法) | lpush |
RPUSH key value1 value2 … | 设置一个key,从尾部插入数据(尾插法) | rpush |
LRANGE key startIndex endIndex | 返回列表中从开始索引到结束索引位置的value值 | lrange |
LPOP key | 从key头部弹出一个value | lpop |
RPOP key | 从尾部弹出一个value | rpop |
LINDEX index | 返回key中指定索引的value值 | lindex |
LREM key n value | 删除key中的指定的value值,n代表删除几个 | lrem |
LLEN key | 返回key的长度 | llen |
LTRIM key startIndex endIndex | 截取key,截取的范围从开始索引到结束索引 | ltrim |
LSET key index value | 从当前key的索引开始插入指定的value值 | lset |
RPOPLPUSH key1 key2 | 从key1的尾部弹出一个元素,将此元素从key2的头部插入 | (转移) |
LINSERT key BEFORE | 从指定key中已存在的value的前面插入一个指定的value | |
AFTER oldValue newValue | 从指定key后面插入一个指定的value |
1、插入
127.0.0.1:6379> lpush mylist a b c # 头插法
3
127.0.0.1:6379> lrange mylist 0 2 # 查看
c
b
a
127.0.0.1:6379> RPUSH list2 a b c #尾插法
3
127.0.0.1:6379> lrange list2 0 2
a
b
c
127.0.0.1:6379> llen list2 # 返回长度
2
2、弹出
127.0.0.1:6379> lpop mylist # 头出
c
127.0.0.1:6379> lrange mylist 0 2
b
a
127.0.0.1:6379> rpop list2 #尾出
c
127.0.0.1:6379> lrange list2 0 2
a
b
127.0.0.1:6379> lindex list2 1 # 定位
b
127.0.0.1:6379> lpush list4 a b c d
4
127.0.0.1:6379> LREM list4 2 b # 删除
1
127.0.0.1:6379> lrange list4 0 8
d
c
a
3、截取
127.0.0.1:6379> lpush list3 a b c d
4
127.0.0.1:6379> ltrim list3 1 2 # 截取
OK
127.0.0.1:6379> lrange list3 0 8
c
b
127.0.0.1:6379> lpush list4 a b c d
4
127.0.0.1:6379> RPOPLPUSH list3 list4 # 转移
sss
127.0.0.1:6379> lrange list4 0 8
sss
d
c
b
a
4、指定value插入
127.0.0.1:6379> lpush list5 a b c d
4
127.0.0.1:6379> lrange list5 0 -1
d
c
b
a
127.0.0.1:6379> lrange list5 0 8
d
c
b
a
127.0.0.1:6379> linsert list5 before b ssr # 从指定 value值的前面 插入
5
127.0.0.1:6379> lrange list5 0 8
d
c
ssr
b
a
127.0.0.1:6379> linsert list5 after b ddt # 从指定 value值的后面 插入
7
127.0.0.1:6379> lrange list5 0 8
d
c
ssr
b
ddt
a
4.3 set(集合)
set集合无序不重复
命令 | 作用 | 关键词 |
---|---|---|
SADD key value1 value2 … | 设置一个key | sadd |
SMEMBERS key | 查看当前key | smembers |
SISMEMBER key value | 查看key中指定的value是否存在 | sismember |
SCARD key | 查看key的长度 | scard |
SREM key value | 删除key中的指定value | srem |
SPOP key | 随机删除key中的一个value | spop |
SRANDMEMBER key [n] | 随机查看当前key中的一个或者多个value | srandmember |
SMOVE key1 key2 key1Value | 将key1中的value移动到key2中 | smove |
SDIFF key1 key2 | 两个key相交,求第一个key的补集 | sdiff |
SINTER key1 key2 | 两个key相交,求交集 | sinter |
SUNION key1 key2 | 两个key相交,求并集 | sunion |
1、设置set
127.0.0.1:6379> sadd set1 a b c # 向集合添加元素
3
127.0.0.1:6379> smembers set1 # 查看所有
c
b
a
127.0.0.1:6379> sadd set1 a b c # 集合无序不重复
0
127.0.0.1:6379> sadd set1 d
1
127.0.0.1:6379> smembers set1
d
c
b
a
127.0.0.1:6379> scard set1 # 查看key的长度
4
2、删除
127.0.0.1:6379> sismember set1 a # 查看key中指定的value是否存在
1 # 1 表示存在
127.0.0.1:6379> sismember set1 s
0 # 1 表示不存在
127.0.0.1:6379> SMEMBERS set1 # 查看所有
d
c
b
a
127.0.0.1:6379> srem set1 d # 指定的value
1
127.0.0.1:6379> spop set1 # 随机删除
c
127.0.0.1:6379> SMEMBERS set1
b
a
127.0.0.1:6379> sadd set2 f g
2
127.0.0.1:6379> smove set2 set1 f # 移动
1
127.0.0.1:6379> SMEMBERS set1
f
b
a
127.0.0.1:6379> SRANDMEMBER set1 # 随机抽取
f
2、集合
生活中的一个小现象,就比如说微信公众号,会有共同关注,还有QQ的共同好友
数学集合关系中的:交、并、补。微信公众号中的共同关注,以及QQ的共同好友,就是关系中的交!
127.0.0.1:6379> sadd set3 a b c
3
127.0.0.1:6379> sadd set4 a c d
3
127.0.0.1:6379> sdiff set3 set4 # 求第一个key的补集
b
127.0.0.1:6379> sinter set3 set4 # 求交集
c
a
127.0.0.1:6379> sunion set3 set4 # 求交集
c
b
a
d
命令都可以在英语单词中找到一些规律
把SDIFF、SINTER还有SUNION这三个单词首字母去掉,可以得到
DIFF:different,它代表不同的,用一句Redis官网的翻译来描述:返回的集合元素是第一个key的集合与后面所有key的集合的差集
INTER:intersection,翻译过来为交叉,同样的,意指数学关系中的交集
UNION:union,翻译为联合,与数学关系中的并集也是可以沾边的
4.4 Hash(哈希)
Redis中的哈希,本质上KV相同但是KV中的V,它也是一个键值对,本质和操作字符串区别不大
命令 | 作用 | 关键字 |
---|---|---|
HSET key field value | 设置单个hash | hset |
HGET key field | 获取单个 | hget |
HMSET key field1 v1 field2 v2 | 设置多个 | hmset |
HMGET key field | 获取多个 | hmget |
HGETALL key | 获取hash中全部的field-value | hgetall |
HLEN key | 获取hash长度 | hlen |
HEXISTS key field | 查询hash中指定的field是否存在 | hexists |
HKEYS key | 只获取hash中的field | hkeys |
HVALS key | 只获取hash中value | hvals |
HINCRBY key field n | 对hash中指定的field设置自增自减 | hincrby |
1、创建hash
127.0.0.1:6379> hset hash1 name zs # 设置单个 hash
1
127.0.0.1:6379> hget hash1 name # 获取单个 hash
zs
127.0.0.1:6379> hmset hash2 name joy age 23 # 设置多个
OK
127.0.0.1:6379> hmget hash2 name age # 获取多个
joy
23
2、获取
127.0.0.1:6379> hgetall hash1 # 获取hash中全部的 键值对
name
zs
127.0.0.1:6379> hlen hash1 # 获取长度
1
127.0.0.1:6379> hkeys hash2 # 获取全部的键
name
age
127.0.0.1:6379> hvals hash2 # 获取全部的值
joy
23
127.0.0.1:6379> hset hash3 age 23
1
127.0.0.1:6379> hincrby hash3 age 25 # 自增23
48
3、使用“:”
可以使用hash做一些临时变更的数据,可以是用户信息,或者是经常变动的信息,上面的String也提到了使用“:”进行层次分割,不过hash更适合对象存储,String适合于文本的存储
127.0.0.1:6379> HMSET user:1 name xiaohuang age 21 sex boy
OK
127.0.0.1:6379> HGETALL user:1
1) "name"
2) "xiaohuang"
3) "age"
4) "21"
5) "sex"
6) "boy"
4.5 Zset(有序集合)
在set的基础上增加了一个score的值,相当于zset k1 score v1,使用score来对当前key中元素进行排序
命令 | 作用 | 关键字 |
---|---|---|
ZADD key score1 value1 score2 value2 … | zset中添加一个或多个元素 | zadd |
ZRANGE key startIndex endIndex | 查询从开始到结束索引的zset集合 | zrange |
ZRANGEBYSCORE key min max [WITHSCORES] | 对hash中按照指定数值进行升序排列 | |
ZREVRANGE key startIndex endIndex | 对指定开始和结束索引进行降序排列 | |
ZREM key field | 删除hash中指定的field | zrem |
ZCARD key | 查询hash长度 | zcard |
ZCOUNT key [min max] | 查询hash数量,还可以增加最大值和最小值的范围 | zcount |
1、
127.0.0.1:6379> zadd set1 1 one # 添加一个元素
1
127.0.0.1:6379> zadd set1 2 tew 3 three # 添加多个元素
2
127.0.0.1:6379> zrange set1 0 -1 # 查询从开始到结束索引的zset集合
one
tew
three
127.0.0.1:6379>
2、实现元素的排序
# 根据zset中score的值来实现元素的排序
127.0.0.1:6379> ZADD salary 3500 xiaohong 6500 xiaohuang 3900 zhangsan
(integer) 3
# 当前命令,inf在Unix系统中代表的意思是无穷,所以当前命令是指,将当前zset,以从小到大的形式进行排列
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
1) "xiaohong"
2) "zhangsan"
3) "xiaohuang"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 在排列的同时,将score和指定的元素全部展示
1) "xiaohong"
2) "3500"
3) "zhangsan"
4) "3900"
5) "xiaohuang"
6) "6500"
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores # 将数据从大到小进行排列
1) "xiaohuang"
2) "6500"
3) "zhangsan"
4) "3900"
5) "xiaohong"
6) "3500"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 4000 withscores # 展示的同时还可以指示score的查询最大值,指定查询范围
1) "xiaohong"
2) "3500"
3) "zhangsan"
4) "3900"
127.0.0.1:6379> ZREM salary zhangsan # 删除zset中的一个元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "xiaohong"
2) "xiaohuang"
127.0.0.1:6379> ZCARD salary
(integer) 2
3、
127.0.0.1:6379> ZADD myset 1 hello 2 world 3 xiaohuang 4 xiaohei 5 xiaolan
(integer) 5
# 语法:ZCOUNT key min max ,min和max包左也包右,它是一个闭区间
127.0.0.1:6379> ZCOUNT myset 2 5 # 获取指定区间的成员数量
(integer) 4
127.0.0.1:6379>
其他
其他的API,如果说在工作中出现了,可以查看Redis的官方文档:http://www.redis.cn/commands.html
案例:zset是Redis的数据类型,可以排序,生活中也有案例,班级成绩,员工工资
设置权重,1、普通消息;2、重要消息;添加权重进行消息判断其重要性
来一个更接地气的案例,可以打开B站,排行榜,B站会根据视频的浏览量和弹幕量进行综合评分,进行排名
5、三种特殊数据类型
5.1 geospatial 地理位置
微信朋友圈中的朋友的位置,或者是QQ中也有的附近的人,饿了么中外卖小哥的位置距离
这个在Redis中被定为特殊的数据类型可叫做Geo,它是Redis3.2正式推出的一个特性,可以推导出两个地方的地理位置,两地之间的距离,方圆几千米之内的人。
对于这个关于地理的数据类型,它有6个命令
关键词 | 命令 | 作用 |
---|---|---|
geoadd | GEOADD key 经度 纬度 城市名称 | 添加地理位置 |
geodist | GEODIST key member1 member2 [unit] | 指定两个位置的距离 |
geohash | GEOHASH key member | 返回一个或多个元素的GeoHash表示,该命令返回11个字符组成的GeoHash字符串 |
geopos | GEOPOS key member1 member2 … | 获取一个或多个地理信息 |
georadius | GEORADIUS key 经度 纬度 半径 [单位] [WITHCOORD(搜寻到的目标的经纬度)] [WITHDIST(直线距离)] [count] | 自己所在的地址为圆心,半径查找 |
georadiusbymember | GEORADIUSBYMEMBER key member 长度 [unit]单位 | 找出指定元素周围的其他元素,就是以城市为中心,一定长度为半径搜索 |
因为这个特殊的数据类型和地理相关,需要用到地理的经纬度,可以推荐一个网站查看指定城市的经纬度:http://www.jsons.cn/lngcode/
1、geoadd 添加地理位置
语法:GEOADD key 经度 纬度 城市名称 …
注意:南北极无法直接添加。用添加城市数据来说,一般都会使用Java的Jedis来操作,而这些城市数据都是被下载下来通过JavaAPI调用
有效经度从-180到180度
有效纬度从-85.05112878 到 85.05112878 度。超过范围会出现(error) ERR invalid longitude,latitude pair
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing 121.47 31.23 shanghai # 添加
2
127.0.0.1:6379> GEOHASH china:city beijing # 返回GeoHash字符串
wx4fbxxfke0
127.0.0.1:6379> ZRANGE china:city 0 -1 # 使用zset命令查看geospatial
shanghai
beijing
127.0.0.1:6379> ZREM china:city beijing # 使用zset的基本命令即可删除
1
127.0.0.1:6379> ZRANGE china:city 0 -1
shanghai
2、geodist
单位:m表示单位米、km表示千米、mi表示英里、ft表示英尺
语法:GEODIST key member1 member2 [unit]
# 查看beijing和shanghai两个位置的直线距离
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing 121.47 31.23 shanghai
1
127.0.0.1:6379> GEODIST china:city beijing shanghai # 单位米
1067378.7564
127.0.0.1:6379> GEODIST china:city beijing shanghai km # 单位千米
1067.3788
3、georadius
自己所在的地址为圆心,半径查找
对于社交软件来说,附近的人,就相当于,你现在所在的地址,再加上一定的半径来进行查找
GEORADIUS key 经度 纬度 半径 [单位] [WITHCOORD(搜寻到的目标的经纬度)] [WITHDIST(直线距离)] [count]
# 以111经度31纬度为中心,1000km为半径搜寻在器范围之内的城市
127.0.0.1:6379> GEORADIUS china:city 111 31 1000 km
1) "shenzhen"
2) "guangzhou"
3) "fuzhou"
4) "shanghai"
# 追加参数,目标经纬度,直线距离
127.0.0.1:6379> GEORADIUS china:city 111 31 1000 km WITHCOORD WITHDIST
# ...
# 还可以限制查询的结果条数,只显示两条
127.0.0.1:6379> GEORADIUS china:city 111 31 1000 km WITHCOORD WITHDIST count 2
1) 1) "guangzhou"
2) "905.0108"
3) 1) "113.27999979257583618"
2) "23.1199990030198208"
# ...
4、GEORADIUSBYMEMBER
找出指定元素周围的其他元素,就是以城市为中心,一定长度为半径搜索
# 找出以shanghai为中心,1000km为半径搜索
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 1000 km
1) "xiamen"
2) "fuzhou"
3) "shanghai"
5.2 Hyperloglog
在讲Hyperloglog之前,什么是基数?
集合中包含的不重复元素即为基数,就比如一个A数据集,A{1,3.7,9,11},它的基数为5,可以接受误差
Hyperloglog是Redis2.8.9更新的,它是一种数据结构,主要是针对于基数统计的算法
优点,占用的内存很小,只需要使用12KB的内存即可统计2^64的数据
在实际业务中,网页的UV(Unique Visitor,独立访客),一个人访问一个网站多次,只能算作是一个,用传统的方式,set集合保存用户的id,然后统计set中元素个数作为标准来判断。使用这种方式来进行数据统计的话,大量的内存用来浪费给保存用户id了,目的是为了计数,而不是为了保存用户id
Hyperloglog计数的错误率在0.81%,用来执行UV任务,可以忽略不计
关键词 | 命令 | 作用 |
---|---|---|
pfadd | PFADD key value1 value2… | 创建一组数据集,如果数据集中有相同的元素就会有去重效果 |
pfcount | PFCOUNT key | 查看元素的长度 |
pfmerge | PFMERGE key3 key1 key2 | 将两组元素合并成一个新数组,并带有去重效果,相当于数学中的并集 |
127.0.0.1:6379> pfadd pf1 a b c d e f g h i j # 创建
1
127.0.0.1:6379> pfcount pf1 # 查看元素的长度
10
127.0.0.1:6379> pfadd pf2 1 2 3 4
1
127.0.0.1:6379> PFMERGE pf1 pf2 # 合并数组
OK
127.0.0.1:6379> pfcount pf1
14
如果在项目中允许容错,可以使用Hyperloglog
如果不行,就可以直接使用set或者Java的HashMap来实现
5.3 Bitmaps
Bitmaps是一种位存储的数据类型,在Redis2.2.0被推出,
生活中可以实现的场景,统计活跃用户,在线状态,用户签到,这些都是表示两种状态之间的,可以使用Bitmaps
Bitmaps,译为位图,也是一种数据结构,操作二进制位进行记录,只有0和1两种状态。Bitmaps通过最小的单位bit来进行存储