可以在bilibili搜索Redis来学习视频 (狂神说)
Redis入门
概述
官网:https://redis.io/
中文网:https://www.redis.cn/
Redis(Remote Dictionary Server),即远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis会周期性的吧更新的数据库写入磁盘或者把修改操作写入追加记录文件,并且在此基础上实现了master-slave(主从)同步。
redis的作者,叫Salvatore Sanfilippo,来自意大利的西西里岛,居住在卡塔尼亚。目前供职于Pivotal公司。他使用的网名是antirez。
常用命令:
TYPE key — 用来获取某key的类型
KEYS pattern — 匹配所有符合模式的key,比如KEYS * 就列出所有的key了,当然,复杂度O(n)
RANDOMKEY – 返回随机的一个key
RENAME oldkeynewkey— key也可以改名
列表操作,精华
RPUSH key string — 将某个值加入到一个key列表末尾
LPUSH key string — 将某个值加入到一个key列表头部
LLEN key — 列表长度
LRANGE key start end — 返回列表中某个范围的值,相当于mysql里面的分页查询那样
LTRIM key start end — 只保留列表中某个范围的值
LINDEX key index — 获取列表中特定索引号的值,要注意是O(n)复杂度
LSET key index value — 设置列表中某个位置的值
LPOP key
RPOP key — 和上面的LPOP一样,就是类似栈或队列的那种取头取尾指令,可以当成消息队列来使用了
集合操作
SADD key member — 增加元素
SREM key member — 删除元素
SCARD key — 返回集合大小
SISMEMBER key member — 判断某个值是否在集合中
SINTER key1 key2 … keyN — 获取多个集合的交集元素
SMEMBERS key — 列出集合的所有元素
还有Multiple DB的命令,可以更换db,数据可以隔离开,默认是存放在DB 0
Redis能干嘛
1、 内存存储、持久化,内存中事断点即失,所以说持久化很重要(rdb、aof)
2、 效率高,可以用于高速缓存
3、 发布订阅系统
4、 地图信息分析
5、 计时器、计数器(浏览量)
6、 ……
特性
1、 多样的数据类型
2、 持久化
3、 集群
4、 事务
5、 ……
下载地址:就是官网中的download下
安装
Windows安装
1、 去Github上下载
2、 下载好的包复制到配置环境的目录下,解压即可
3、 开启redis,双击运行redis-server.exe,默认端口号:6379
4、 使用redis客户端来连接redis,双击redis-cli.exe。输入命令:ping
看到输出POMG代表连接成功
Linux安装
长时间没有用XShell发现评估期已经过了
解决方法:首先卸载要收费的版本,安装免费的版本
1)登录NetSarang公司(xshell开发者)官网下载页面和提前登录QQ邮箱:
https://www.netsarang.com/zh/free-for-home-school/
2)点击下载之后弹出这个页面
3) QQ邮箱就会收到下载链接
等待下载完成,然后点击安装
- 安装好后会直接弹出新建会话,那就直接新建会话即可。
新建会话中的主机可以填写虚拟机上的,打开虚拟机,然后随便选择一个连接上后,输入ifconfig查看
将上面的ip复制,然后在新建会话中的主机上粘贴即可
点击连接会出现。要是点击了确定的话也不要着急,在刚刚新建的会话中再次点击一下即可,这时还是会弹出SSH安全警告
一样弹出安全警告
直接点击接受并保存,会出现下面这种情况,选择是或者否都可以
如果点击是,就会去下载页面
跳转页面,填写信息
- 安装Xftp7,下载完毕后直接点击安装,安装完成即可。
提示:上面只是解决燃眉之急而已,因为这是只有30天的评估期,评估期一过还是会弹出叫你购买的弹窗。上面的步骤完成后,接下来就安装redis
1、下载安装包,在官网中直接下载,下载完成打开xshell,点击xftp
直接在左边上找到下载好的redis拖拽到右边即可
如果在C盘下,进不到root目录中
打开VMware虚拟机,连接终端,输入ifconfig
,找到ip
复制下来,在电脑打开cmd ,输入ping 192.168.12.128
,如果没出先0%的丢失就继续运行直到出现为止
然后会到Xshell新建会话
此时就可以看到进入到了root。这时cd进入home目录再进入到自己在xftp中新建好的目录,ls列出所有文件,可以看到上传redis成功
另外Xftp连接上虚拟机后还有乱码的朋友请戳
https://blog.csdn.net/Yao1100000/article/details/109095042 也就是在xftp–文件–属性–选项–编码–选择UTF-8即可
注意:后期如果想要进入root,那就一定要先打开虚拟机并且开启该虚拟机才行
2、解压Redis安装包。这个是程序,所以一般放到/opt的目录下,移动过去即可 rm redis-6.2.4.tar.gz /opt
3、解压,tar -zxvf redis-6.2.4.tar.gz
4、解压完后可以cd redis-6.2.4
然后ls查看
5、安装gcc(基本的环境),yum install gcc-c++
。运行到后面,问你确定是否安装(有两个询问),确定即可。然后安装完成输入gcc -v可以查看是否可以使用
接着输入make命令,但是如果没有安装过一个支持make命令的包会提示你是否安装,确认就行。安装完毕再make,想要查看安装情况,执行make install
6、 redis的默认安装路径 /usr/local/bin
7、 新建一个目录mkdir redisconfig 将redis下的conf目录复制到redisconfig文件夹里面
cp /opt/redis-6.2.4/redis.conf redisconfig
8、 redis默认不是后台启动,需要修改配置。
vim redis.conf 找到daemonize将no改成yes
按i进入插入(编辑)模式
按esc然后输入:wq(保存文件,退出vim命令)
:w(保存文件,不退出vim命令)
:q!(不保存文件,强制退出vim命令)
9、 启动redis服务
pwd是print working directory的缩写,打印当前工作目录,就是显示当前所在目录的意思
但是其实这样就是启动的了
10、 使用Linux客户端进行连接 输入redis-cli -p 6379
keys * 查看数据库所有的key
11、查看redis进程 ps -ef|grep redis
ps命令将某个进程显示出来
grep命令是查找
中间的|是管道命令 是指ps命令与grep同时执行
PS是LINUX下最常用的也是非常强大的进程查看命令
12、关闭redis服务 shutdown 然后exit退出
测试性能
官方自带的性能测试工具redis-benchmark,一个压力测试工具
测试
#100个并发连接 10万次请求
#连接本地(127.0.0.1)的redis默认端口号,100个并发连接 10万次请求,-q强制退出redis
redis-benchmark -h localhost -p 6379 -c 100 -n 100000 -q
基础知识
Redis默认有16个数据库。默认使用的是第0个数据库
可以使用select进行切换
往数据库里面写值的话,那就只是在4这个数据库,不关其他数据库的事。即不同的数据库可以存不同的值
清空数据库
flushdb清空当前库
flushall清空所有数据库内容
Redis的端口号6379有一个历史,跟MySQL的默认端口号3306也有一个历史
Redis是单线程的
Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了
Redis是C语言写的,官方提供的数据为 100000+ 的QPS,完全不比同样使用key-value的Memecache差。
Redis为什么单线程还这么快
1、 误区1:高性能的服务器一定是多线程的
2、 误区2:多线程(CPU上下文会切换)一定比单线程效率高
要对CPU、内存、硬盘的速度有所了解,CPU > 内存 > 硬盘
核心:redis将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作),对于内存系统来说如果没有上下文切换,效率就是最高的。多次读写都是在一个CPU上的,在内存下,这个就是最佳方案
五大数据类型
Redis-Key
首先连接好redis,确保客户端跟服务端是连接的
127.0.0.1:6379> flushall #清空所有数据
OK
127.0.0.1:6379> set name changan #set一个key
OK
127.0.0.1:6379> keys * #查看所有的key
1) "name"
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name # 判断当前的key是否存在
(integer) 1 #返回1证明存在
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 1 #移除当前的key
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name gucheng
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> get name
"gucheng"
127.0.0.1:6379> expire name 10 #设置key的过期时间。单位是s
(integer) 1
127.0.0.1:6379> ttl name #查看过期的进度,如果为-2证明上面的10s已经过去
(integer) 1 # 1代表还有1s就会过期
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name gucheng
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> type name #查看当前key的类型
string
127.0.0.1:6379> type age
string
127.0.0.1:6379>
String(字符串)
127.0.0.1:6379> flushdb
OK
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 #判断某一个key是否存在
(integer) 1
127.0.0.1:6379> append key1 "china" #追加字符串,如果当前key不存在,就相当于set了一个key
(integer) 7
127.0.0.1:6379> get key1
"v1china"
127.0.0.1:6379> strlen key1 #获取字符串的长度
(integer) 7
127.0.0.1:6379> append key1 ",cidu"
(integer) 12
127.0.0.1:6379> get key1
"v1china,cidu"
###########################
# i++ 步长 i+=
# set title:100:views 0 #设置title的第100篇文章浏览量为0
127.0.0.1:6379> set views 0 #初始浏览量为0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增1 浏览量+1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> decr views #自减1 浏览量-1
(integer) 0
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incrby views 9 #可以设置步长,指定增量(一次增加9条数据)
(integer) 9
127.0.0.1:6379> decrby views 2 #一次减少2条数据
(integer) 7
################################
# 字符串范围 range
127.0.0.1:6379> set key1 "vigorous,life" #设置key1值
OK
127.0.0.1:6379> get key1
"vigorous,life"
127.0.0.1:6379> getrange key1 1 5 #截取从[1,5]长度的字符串
"igoro"
127.0.0.1:6379> getrange key1 0 -1 #获取全部的字符串 和 get key一样
"vigorous,life"
#### 替换
127.0.0.1:6379> set key2 beautiful
OK
127.0.0.1:6379> get key2
"beautiful"
127.0.0.1:6379> SETRANGE key2 3 xxx #替换指定位置开始的字符串,索引从0开始
(integer) 9
127.0.0.1:6379> get key2
"beaxxxiful"
################################
# setex(set with expire)设置过期时间 setnx (set with not exist)设置不存在的值(在分布式锁中会常常使用)
127.0.0.1:6379> get key2 "beaxxiful"
127.0.0.1:6379> setex key3 25 "guangzhou" #设置key3的值为 guangzhou,25秒后过期
OK
127.0.0.1:6379> ttl keys
(integer) -2
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> setnx indexkey "redis" #如果indexkey 不存在,创建indexkey
(integer) 1
127.0.0.1:6379> setnx indexkey "shenzhen" #如果indexkey存在,创建失败
(integer) 0 #返回0说明创建失败
127.0.0.1:6379> get indexkey
"redis"
################################
# mset mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k7 v7 # msetnx 是一个原子性的操作,要么成功要么失败
(integer) 0 #返回0说明失败
127.0.0.1:6379> get k7
(nil)
#对象
set user:1{name:Guangdong,age:600} #设置一个user:1对象,值为json字符来保存一个对象
# 这里的key设计:user:{id}:{filed}(属性),这个设计在Redis是完全OK的
127.0.0.1:6379> mset user:1:name gaungdong user:1:age 600
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "gaungdong"
2) "600"
################################
# getset #首先get再set
127.0.0.1:6379> getset sys redis #如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get sys
"redis"
127.0.0.1:6379> getset sys studentsys #如果存在值,获取原来的值,并设置新的值
"redis"
127.0.0.1:6379> get sys
"studentsys"
String类似的使用场景:value除了字符串还可以是数字
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
List
基本的数据类型,列表
在Redis中,可以把list玩成栈、对列、阻塞队列
所有的list命令都以l开头
127.0.0.1:6379> lpush list Guangzhou #将一个或者多个值插入到列表的头部(左)
(integer) 1
127.0.0.1:6379> lpush list shenzhen
(integer) 2
127.0.0.1:6379> lpush list foshan
(integer) 3
127.0.0.1:6379> lrange list 0 -1 #获取list中的值
1) "foshan"
2) "shenzhen"
3) "guangzhou"
127.0.0.1:6379> lrange list 1 2 #通过区间获取具体的值
1) "shenzhen"
2) "guangzhou"
127.0.0.1:6379> rpush list donggaun #将一个或者多个值插入到列表的尾部(右)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "foshan"
2) "shenzhen"
3) "guangzhou"
4) "donggaun"
############################
#pop,移除
127.0.0.1:6379> lpop list #移除list的第一个元素
"foshan"
127.0.0.1:6379> rpop list #移除list的最后一个元素
"donggaun"
127.0.0.1:6379> lrange key 0 -1
(empty array)
127.0.0.1:6379> lrange list 0 -1
1) "shenzhen"
2) "guangzhou"
############################
# lindex
127.0.0.1:6379> lindex list 1 #通过下标获得list中的某一个值
"guangzhou"
127.0.0.1:6379> lindex list 0
"shenzhen"
############################
# llen 返回长度
127.0.0.1:6379> lpush list baiyunqu
(integer) 1
127.0.0.1:6379> lpush list panyuqu
(integer) 2
127.0.0.1:6379> lpush list yuexiuqu
(integer) 3
127.0.0.1:6379> llen list #返回列表的长度
(integer) 3
############################
# lrem移除指定的值
# 取关 uid
127.0.0.1:6379> lrem list 1 yuexiuqu #移除list集合中指定个数的value,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "tianhequ"
2) "panyuqu"
3) "baiyunqu"
127.0.0.1:6379> lpush list tianhequ
(integer) 4
127.0.0.1:6379> lrem list 2 tianhequ #移除list集合中2个tianhqu的值
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "panyuqu"
2) "baiyunqu"
############################
# trim 修剪 。list截断
127.0.0.1:6379> rpush redislist "zhongshandaxve"
(integer) 1
127.0.0.1:6379> rpush redislist "huananligongdaxve"
(integer) 2
127.0.0.1:6379> rpush redislist "guangdongzhongyiyaodaxve"
(integer) 3
127.0.0.1:6379> rpush redislist "xinghaidaxve"
(integer) 4
127.0.0.1:6379> ltrim redislist 0 1 #通过下标截取指定的长度,其他的被删除了
OK
127.0.0.1:6379> lrange redislist 0 -1
1) "zhongshandaxve"
2) "huananligongdaxve"
############################
# rpoplpush #移除列表的最后一个元素,将之移动到新的列表中
127.0.0.1:6379> rpush list "beijing"
(integer) 1
127.0.0.1:6379> rpush list "shanghai"
(integer) 2
127.0.0.1:6379> rpush list "guangdong"
(integer) 3
127.0.0.1:6379> rpoplpush list anotherlist # 从list列表中 移动guangdong这个元素到新 的列表anotherlist中
"guangdong"
127.0.0.1:6379> lrange list 0 -1
1) "beijing"
2) "shanghai"
127.0.0.1:6379> lrange anotherlist 0 -1
1) "guangdong"
############################
# lset 将列表中指定索引的值替换为另外一个值,更新操作
127.0.0.1:6379> lpush list "v1"
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "v1"
127.0.0.1:6379> lset list 0 index #如果存在就更新当前下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "index"
127.0.0.1:6379> lset list 1 item #如果不存在列表就去更新会报错
(error) ERR index out of range
############################
# linsert 将某个具体的value插入列表中某个元素的前或者后面
127.0.0.1:6379> linsert list world
(error) ERR wrong number of arguments for 'linsert' command
127.0.0.1:6379> rpush list world
(integer) 1
127.0.0.1:6379> rpush list universe
(integer) 2
127.0.0.1:6379> linsert list before "universe" "themilkyway" #在universe前面面添加一个元素themilkyway
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "world"
2) "themilkyway"
3) "universe"
127.0.0.1:6379> linsert list after "universe" "multiverse" #在universe后面添加一个##元素multiverse
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "world"
2) "themilkyway"
3) "universe"
4) "multiverse"
List小结
1) 他实际是一个链表,before Node after,left,right都可以插入值
2) 如果key不存在,创建新的链表
3) 如果key存在,新增内容
4) 如果移除了所有值,空链表,也代表不存在
5) 在两边插入或者改动值,效率最高,中间元素相对来说效率会低一点
消息排队,消息队列(LPUSH rpop),栈(lpush lpop)
Set(集合)
set的所有命令是s开头
set中的值是不能重复的
127.0.0.1:6379> sadd set "qinshihuang" #set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd set "yandi"
(integer) 1
127.0.0.1:6379> sadd set "wuzetian"
(integer) 1
127.0.0.1:6379> smembers set #查看指定的set的所有值
1) "wuzetian"
2) "yandi"
3) "qinshihuang"
127.0.0.1:6379> sismember set tanggaozong #判断某一个值是不是在set集合中
(integer) 0 #返回0代表否
############################
# scard 获取集合中的个数
127.0.0.1:6379> scard set #获取set集合中的内容元素个数
(integer) 3
############################
# srem 移除集合中的元素
127.0.0.1:6379> srem set zhuyuanzhang #移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> scard set
(integer) 3
127.0.0.1:6379> smembers set
1) "wuzetian"
2) "yandi"
3) "qinshihuang"
############################
# set 无序不重复集合,抽随机
127.0.0.1:6379> srandmember set #随机抽选出一个元素
"yandi"
127.0.0.1:6379> srandmember set
"wuzetian"
127.0.0.1:6379> srandmember set 2 #随机抽选出指定(2)个数的元素
1) "wuzetian"
2) "qinshihuang"
127.0.0.1:6379> srandmember set 2
1) "yandi"
2) "wuzetian"
############################
# spop 删除指定的key,随机删除key
127.0.0.1:6379> spop set #随机删除set集合中的元素
"qinshihuang"
127.0.0.1:6379> smembers set
1) "wuzetian"
############################
# smove 将一个指定的值,移动到另外一个set集合
127.0.0.1:6379> sadd redisset "today"
(integer) 1
127.0.0.1:6379> sadd redisset "tomorrow"
(integer) 1
127.0.0.1:6379> sadd redisset "yesterday"
(integer) 1
127.0.0.1:6379> sadd redisset "day"
(integer) 1
127.0.0.1:6379> smove redisset redisset2 "day" # 将redisset中一个指定的值,移动到另外一个redisset2集合中
(integer) 1
127.0.0.1:6379> smembers redisset2
1) "day"
127.0.0.1:6379> smembers redisset
1) "tomorrow"
2) "yesterday"
3) "today"
############################
# smove 共同关注(微博,B站)
# 数字集合类:差集:sdiff、交集:sinter、并集:sunion
127.0.0.1:6379> sadd hey1 ge
(integer) 1
127.0.0.1:6379> sadd hey1 shi
(integer) 1
127.0.0.1:6379> sadd hey1 bai
(integer) 1
127.0.0.1:6379> sadd hey2 bai
(integer) 1
127.0.0.1:6379> sadd hey2 qian
(integer) 1
127.0.0.1:6379> sadd heye ge
(integer) 1
127.0.0.1:6379> sdiff hey1 hey2 #差集
1) "ge"
2) "shi"
3) "bai"
127.0.0.1:6379> sinter hey1 hey2 #交集
1) "bai"
127.0.0.1:6379> sunion hey1 hey2 #并集
1) "qian"
2) "ge"
3) "shi"
4) "bai"
举例子,微博,A用户将所有关注的人放在一个集合中,将它的粉丝也放在一个集合中。然后可查看共同关注,共同爱好的,还可以成为二度好友(六度分割理论)
Hash(哈希)
Map集合,key-Map<key,value>集合,这个value是map集合了。本质和String类型没有太大区别,还是一个简单的key-value
所有的hash命令都以h开头
127.0.0.1:6379> hset hashnow field1 Monday #设置一个具体的key-value
(integer) 1
127.0.0.1:6379> hget hashnow field1 #获取一个字段值
"Monday"
127.0.0.1:6379> hmset hashnow field1 Tuesday field2 Wednesday #set多个key-value
OK
127.0.0.1:6379> hmget hashnow field1 field2 #获取多个字段值
1) "Tuesday"
2) "Wednesday"
127.0.0.1:6379> hgetall hashnow #获取全部的数据
1) "field1"
2) "Tuesday"
3) "field2"
4) "Wednesday"
127.0.0.1:6379> hdel hashnow field1 #删除hashnow中指定的key字段。对应的value中也消失了
(integer) 1
127.0.0.1:6379> hgetall hashnow
1) "field2"
2) "Wednesday"
############################
# hlen 获取长度
127.0.0.1:6379> hmset hashnow field1 FromoMonday field2 ToFriday
OK
127.0.0.1:6379> hgetall hashnow
1) "field2"
2) "ToFriday"
3) "field1"
4) "FromoMonday"
127.0.0.1:6379> hlen hashnow #获取hash表的字段数量
(integer) 2
############################
# hexists 判断某个值是否存在
127.0.0.1:6379> hexists hashnow field1 #判断hash中的指定字段是否存在
(integer) 1
127.0.0.1:6379> hexists hashnow field3
(integer) 0
############################
# hkeys 只获得所有的key ;hvals 只获得所有value
127.0.0.1:6379> hkeys hashnow #只获得所有的field(字段)
1) "field2"
2) "field1"
127.0.0.1:6379> hvals hashnow #只获得所有的value(值)
1) "ToFriday"
2) "FromoMonday"
############################
# hincr hdecr
127.0.0.1:6379> hset hashnow field3 1000 #指定增量为1000
(integer) 1
127.0.0.1:6379> hincrby hashnow field3 200 #指定增量
(integer) 1200
127.0.0.1:6379> hincrby hashnow field3 -20
(integer) 1180
127.0.0.1:6379> hsetnx hashnow field4 history #如果不存在则可以设置
(integer) 1
127.0.0.1:6379> hsetnx hashnow field4 story #如果存在则不可以设置
(integer) 0
# hash可以存变更数据 user name age
127.0.0.1:6379> hset user:1 name china
(integer) 1
127.0.0.1:6379> hget user:1 name
"china"
Hash变更的数据,尤其是用户信息之类的,经常变动的信息,hash更适合于对象的存储,String更适合字符串存储
Zset(有序集合)
在set的基础上增加了一个值,set k1 v1 ;zset k1 score1 v1
所有的zset命令都以z开头
############################
127.0.0.1:6379> zadd setit 1 shuihuzhuan #添加一个值
(integer) 1
127.0.0.1:6379> zadd setit 2 xiyouji 3 hongloumeng #添加多个值
(integer) 2
127.0.0.1:6379> zrange setit 0 -1
1) "shuihuzhuan"
2) "xiyouji"
3) "hongloumeng"
############################
# zrangebyscore 排序
127.0.0.1:6379> zadd salary 4682 chengxvyuan #添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 10800 java
(integer) 1
127.0.0.1:6379> zadd salary 6000 c#
(integer) 1
## zrangebyscore key min max
127.0.0.1:6379> zrangebyscore salary -inf +inf #显示全部用户,从小到大排序(负无穷-inf,正无穷+inf)
1) "chengxvyuan"
2) "c#"
3) "java"
127.0.0.1:6379> zrevrange salary 0 -1 #(薪水)成绩从大到小排序
1) "java"
2) "c#"
127.0.0.1:6379> zrangebyscore salary +inf -inf
(empty array)
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #显示全部用户并且附带成绩(薪水)
1) "chengxvyuan"
2) "4682"
3) "c#"
4) "6000"
5) "java"
6) "10800"
127.0.0.1:6379> zrangebyscore salary -inf 6000 withscores #显示工资小于6000的员工的升序排列
1) "chengxvyuan"
2) "4682"
3) "c#"
4) "6000"
############################
# zrem 移除元素
127.0.0.1:6379> zrange salary 0 -1
1) "chengxvyuan"
2) "c#"
3) "java"
127.0.0.1:6379> zrem salary chengxvyuan #移除指定的元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1 #查看salary中的所有元素
1) "c#"
2) "java"
127.0.0.1:6379> zcard salary #获取有序集合中的个数
(integer) 2
############################
# zcount 获取区间的成员变量
127.0.0.1:6379> zadd myset 1 dog
(integer) 1
127.0.0.1:6379> zadd myset 2 cat 3 insect
(integer) 2
127.0.0.1:6379> zcount myset 0 2 #获取指定集合中的成员变量[0,2]
(integer) 2
其余的一些 API,通过学习,剩下的如果工作中有需要,这个时候去查看官方文档。
案例思路:set排序 存储班级成绩表,工资表排序
普通消息,1、重要消息2、带权重进行判断
排行榜应用实现,取Top N
三种特殊数据类型
Geospatial(地理位置)
要用到的数据:http://www.jsons.cn/lngcode/ ,下面的一些地址位置经纬度可以点击进去查询。
6个命令
1) GEOADD
2) GEODIST
3) GEOHASH
4) GEOPOS
5) GEORADIUS
6) GEORADIUSBYMEMBER
Getadd 添加地理位置
#规则:两极(南、北)无法直接添加。一般会下载城市数据,直接通过java程序一次性导入
#有效的经度:-180到180 ;有效的纬度:-85.05112878到85.05112878。超出指定范围会返回一个错误
# 127.0.0.1:6379> geoadd china:city 29.66 91.13 lasashi
# (error) ERR invalid longitude,latitude pair 29.660000,91.130000
127.0.0.1:6379> geoadd china:city 91.13 29.66 lasashi
(integer) 1
127.0.0.1:6379> geoadd china:city 126.64 45.75 heilongjiangshi
(integer) 1
127.0.0.1:6379> geoadd china:city 111.67 40.81 huhehaoteshi
(integer) 1
127.0.0.1:6379> geoadd china:city 114.17 22.26 hongkong
(integer) 1
127.0.0.1:6379> geoadd china:city 113.54 22.19 aomen 121.56 25.03 taiwan
(integer) 2
GEODIST
# 两者之前的距离单位
# M:表示单位米;km:表示单位为千米;mi:表示单位英里;ft:表示单位为英尺
127.0.0.1:6379> geodist china:city hongkong heilongjiangshi #查看香港到黑龙江市的直线距离,默认是m
"2846471.3986"
127.0.0.1:6379> geodist china:city hongkong heilongjiangshi km
"2846.4714"
GEOHASH 返回一个或者多个位置元素
127.0.0.1:6379> geohash china:city aomen taiwan #将二维的经纬度转换为一维的字符串,如果两个字符串越接近,则距离越近
1) "webwpxt61g0"
2) "wsqqqht6360"
GEOPOS 获取指定城市经纬度(是一个坐标值)
127.0.0.1:6379> geopos china:city lasashi
1) 1) "91.1300012469291687"
2) "29.66000035782676747"
127.0.0.1:6379> geopos china:city lasashi aomen
1) 1) "91.1300012469291687"
2) "29.66000035782676747"
2) 1) "113.54000240564346313"
2) "22.18999967077372304"
GEORADIUS 以给定的经纬度为中心,找出某一半径内的元素
#查看附近的人?(获得所有附近的人的地址,定位)通过半径来查询
127.0.0.1:6379> georadius china:city 100 30 1000 km # 获取当前经纬度(100 30)这个经纬度为中心,查询方圆1000km内的城市 前提是所有数据都录入china:city中
1) "lasashi"
127.0.0.1:6379> georadius china:city 100 30 5000 km
1) "lasashi"
2) "aomen"
3) "hongkong"
4) "taiwan"
5) "heilongjiangshi"
127.0.0.1:6379> georadius china:city 100 30 5000 km withdist #显示xx到中心距离的位置
1) 1) "lasashi"
2) "856.4817"
2) 1) "aomen"
2) "1605.3969"
3) 1) "hongkong"
2) "1654.1187"
4) 1) "taiwan"
2) "2193.6677"
5) 1) "heilongjiangshi"
2) "2899.0121"
127.0.0.1:6379> georadius china:city 100 30 5000 km withcoord #显示经纬度
1) 1) "lasashi"
2) 1) "91.1300012469291687"
2) "29.66000035782676747"
2) 1) "aomen"
2) 1) "113.54000240564346313"
2) "22.18999967077372304"
3) 1) "hongkong"
2) 1) "114.16999965906143188"
2) "22.26000106503118303"
4) 1) "taiwan"
2) 1) "121.56000047922134399"
2) "25.03000011182229656"
5) 1) "heilongjiangshi"
2) 1) "126.64000242948532104"
2) "45.74999965248261447"
#获得指定数量的人
127.0.0.1:6379> georadius china:city 100 30 5000 km withdist withcoord count 3 #筛选出指定的结果
1) 1) "lasashi"
2) "856.4817"
3) 1) "91.1300012469291687"
2) "29.66000035782676747"
2) 1) "aomen"
2) "1605.3969"
3) 1) "113.54000240564346313"
2) "22.18999967077372304"
3) 1) "hongkong"
2) "1654.1187"
3) 1) "114.16999965906143188"
2) "22.26000106503118303"
GEORADIUSBYMEMBER 找出位于指定元素周围的其他元素
127.0.0.1:6379> georadiusbymember china:city hongkong 3000 km
1) "lasashi"
2) "aomen"
3) "hongkong"
4) "taiwan"
5) "heilongjiangshi"
127.0.0.1:6379> georadiusbymember china:city hongkong 300 km
1) "aomen"
2) "hongkong"
#原理:底层的实现原理其实就是Zset,可以使用Zset命令来操作geo
127.0.0.1:6379> zrange china:city 0 -1 #查看地图中全部元素
1) "lasashi"
2) "aomen"
3) "hongkong"
4) "taiwan"
5) "heilongjiangshi"
127.0.0.1:6379> zrem china:city heilongjiangshi #移除指定元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "lasashi"
2) "aomen"
3) "hongkong
Hyperloglog
优点:占用的内存四固定,2^64不同的元素的技术,只需要12kb内存,如果要从内存角度来比较的话,hyperloglog首选
Redis2.89版本就更新了hyperloglog数据结构
Redis hyperloglog基数统计的算法
网页的UV(一个人访问一个网站多次,但是还是算作一个人)
传统的方式,set保存用户id,然后就可以统计set中的元素数量作为标准判断
这个方式如果保存大量的用户id,就会比较麻烦,我们的目的是为了计数,而不是保存用户id
127.0.0.1:6379> pfadd pfset a s d f g h j k l #创建第一组元素
(integer) 1
127.0.0.1:6379> pfcount pfset #统计第一组元素的基数(不重复)数量
(integer) 9
127.0.0.1:6379> pfadd pfset1 q w e r t y u i o #创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount pfset1
(integer) 9
127.0.0.1:6379> pfmerge pfset2 pfset pfset1 #合并两组元素到新的元素(pfset2)中
OK
127.0.0.1:6379> pfcount pfset2 #查看并集的数量
(integer) 17
如果允许容错,可以使用hyperloglog;不允许的话,使用set或者自己的数据类型
Bitmap(位图,数据结构。都是操作二进制来进行记录,就只有0和1两个状态)
位存储(0和1表示)
统计用户信息,活跃,不活跃。登录,未登录……两个状态的,都可以使用bitmap
举例:一周的打卡时间,索引从0开始,0代表星期一
127.0.0.1:6379> setbit sign 0 1 #签到 0代表周一,1代表已打卡签到
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0 #签到 4代表周五,0代表没有打卡签到
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
#查看某一天是否打卡
127.0.0.1:6379> getbit sign 4 #查看周五是否打卡
(integer) 0 #返回0代表没打卡
127.0.0.1:6379> getbit sign 5
(integer) 1
#统计打卡天数
127.0.0.1:6379> bitcount sign #查看这周的打卡天数,可以查看是否全勤
(integer) 6