Redis(Remote dictionary server)开源的基于内存的数据存储系统
可用于数据库、缓存、队列等各种场景。
支持key-value的储存形式,底层是用C语言编写的。
基于key-value形式的数据字典,结构非常简单,没有数据表的概念,之间用键值对的形式完成数
据的管理。
SQL | NoSQL | |
数据结构 | 结构化(Structured) | 非结构化 |
数据关联 | 关联的(Relational) | 无关联的 |
查询方式 | SQl查询 | 非SQL |
事务特性 | ACID | BASE |
储存方式 | 磁盘 | 内存 |
扩展性 | 垂直 | 水平 |
使用场景 | 1)数据结构固定 2)相关业务对数据安全性、一致性要求较高 | 1)数据结构不固定 2)对一致性、安全性要求不高 3)对性能要求 |
Redis的特征
-
性能极高
-
键值型(Key--Value)、Value支持多种不同数据结构、功能丰富。
-
单线程、每个命令具备原子性
-
低延迟、速度快(基于内存、IO多路复用、良好的编码)
-
数据类型丰富、单键值对最大支持521M大小的数据
-
简单易用,支持所有的主流语言
-
支持数据持久化,主从复制,哨兵模式等高可用特性
Redis的数据结构
基本数据结构:
-
字符串 String
-
列表 Lsit
-
集合 Set
-
有序集合 SortedSet(ZSet)
-
哈希 Hash key:{ key:value }
高级数据结构:
-
消息队列 Stream
-
地理空间 Geospatial
-
HyperLogLog
-
位图 Bitmap
-
位域 Bitfield
Redis的三种使用方式
CLI(Command Line Interface)命令行界面
API(Application Programming Interface)编程使用指定方法
GUI(Graphical User Interface)可视化软件
Redis基本命令
SELECT:切换数据库。例:SELECT 2
DBSIZE:查看数据库中的内容。
FLUSHDB:清空当前数据库。(FLUSHALL---清空所有数据库)
MOVE:将当前数据库的Key移动到制定的数据库。例:MOVE name 1
String(字符串)
- String类型的使用场景:Value除了是字符串也可以是数字!
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
TYPE:查看当前key的类型。例:TYPE name
APPEND:向key后面追加一个字符串。例:APPEND key1 “Hello”
STRLEN:获取字符串的长度。例:STRLEN
Redis中的键和值都是以二进制的形式存储的,默认不支持中文的,可以先quit退出Redis,然后redis-cli --raw表示以原始的形式来显示内容
SET Key Value :设置一个键值。
name与Name的值不一样(Redis中的键区分大小写,Redis默认都是使用字符串来存储数据,且是二进制安全的)
GET: 获取键的值。
DEL :删除一个键 。
EXISTS: 来判断一个键是否存在。(存在为1不存在为0)
KEYS: 用来查看数据库中都有哪些键。例:KEYS * (用来查找数据库中所有的键)、KEYS *me(查找所以以me结尾的键)
CLEAR: 清空屏幕
127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获取值
v1
127.0.0.1:6379> keys * #获取所有的key
key1
127.0.0.1:6379> EXISTS key1 #判断某一个key是否存在
1
127.0.0.1:6379> APPEND key1 "hello" #追加字符串,如果当前key不存在,就相当于setkey
7
127.0.0.1:6379> get key1
v1hello
127.0.0.1:6379> STRLEN key1 #获取字符串长度的长度!
7
127.0.0.1:6379> APPEND key1 "world"
12
127.0.0.1:6379> STRLEN key1
12
127.0.0.1:6379> get key1
v1helloworld
######################################################################################
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
1
127.0.0.1:6379> incr views
2
127.0.0.1:6379> get views
2
127.0.0.1:6379> decr views #自减1 浏览量-1
1
127.0.0.1:6379> decr views
0
127.0.0.1:6379> decr views
-1
127.0.0.1:6379> get views
-1
127.0.0.1:6379> INCRBY views 10 #指定步长,指定增量! 浏览量+10
9
127.0.0.1:6379> INCRBY views 10 #指定步长,指定减量! 浏览量-10
19
127.0.0.1:6379> DECRBY views 10
9
127.0.0.1:6379> get views
9
######################################################################################
# 字符串范围
127.0.0.1:6379> set key1 "hello,world" #设置key1的值
OK
127.0.0.1:6379> get key1
hello,world
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串[0,3]
hell
127.0.0.1:6379> GETRANGE key1 0 -1 #获取全部的字符串 和get key是一样的
hello,world
# 替换!
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
abcdefg
127.0.0.1:6379> SETRANGE key2 1 xx #替换自定位置开始的字符串!
7
127.0.0.1:6379> get key2
axxdefg
######################################################################################
TTL: 查看一个键的过期时间。(-1表示没有设置过期时间,-2表示已经过期)。例:TTL name
127.0.0.1:6379> TTL name
-1
127.0.0.1:6379>
EXPIRE: 来设置一个键的过期时间。例:EXPIRE name 10 (设置name键的过期时间为10秒,同时GET和KEYS也获取不到此键)
127.0.0.1:6379> EXPIRE name 10
1
127.0.0.1:6379> TTL name
8
127.0.0.1:6379> TTL name
2
127.0.0.1:6379> TTL name
0
127.0.0.1:6379> TTL name
-2
127.0.0.1:6379> GET name
127.0.0.1:6379> KEYS *
127.0.0.1:6379>
SETEX: 设置一个带有过期时间的键值对 例:SETEX name 10 hello(设置一个值为hello键为name过期时间为10秒的键值对)
127.0.0.1:6379> SETEX name 10 hello
OK
127.0.0.1:6379>
127.0.0.1:6379> TTL name
7
127.0.0.1:6379> TTL name
4
127.0.0.1:6379> TTL name
-2
127.0.0.1:6379> GET name
127.0.0.1:6379> KEYS *
127.0.0.1:6379>
SETNX: 只有当键不存在时才设置键的值,否则不会做任何动作
127.0.0.1:6379> SETNX name hello
1
127.0.0.1:6379> SETNX name hhh
0
127.0.0.1:6379> GET name
hello
127.0.0.1:6379>
MEST: 同时设置多个值。
MGET: 同时获取多个值。
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
k2
k1
k3
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
v1
v2
v3
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx 是一个原子性的操作,要么一起成功,要么一起失败
0
127.0.0.1:6379> get k4
MSET对象
SET user:1 {name:zhangsan,age:3} #设置一个user:1对象 值为json字符来保存一个对象!
# 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在Redis中完全OK!
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "18"
GETSET:先get再set
127.0.0.1:6379> GETSET db redis # 如果不存在值,则返回nil
(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"
数据结构是相通的 !
List的常用命令(所有的list命令都是以 “ L ” 开头)
LPUSH: 从列表的头部添加元素,可同时添加多个元素 。
RPUSH:从列表的尾部添加元素,也可同时添加多个元素。
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 #获取list中的值
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>
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
LPOP:删除列表中第一一个元素,并返回被删除的元素
RPOP:删除列表中最后一个元素,并返回被删除的元素
LPOP、RPOP也可以一次性删除多个元素。例:LPOP letter 2(表示从列表头部删除2个元素,RPOP也同理)
可以使用LPUSH在列表头部添加元素,再使用RPOP在列表尾部删除一个元素,就实现了一个最简单的先进先出队列
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> LPOP list # 移除list的第一个元素
"three"
127.0.0.1:6379> Rpop list # 移除list的最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
LRANGE:获取列表的内容。例:LRANGE letter 0(起始位置与结束位置都是以0开始)-1(表示最后一个元素)
127.0.0.1:6379> LRANGE letter 0 -1
e
d
c
b
a
127.0.0.1:6379>
LINDEX:通过下标获得list中的某一个值
127.0.0.1:6379> LINDEX list 1 # 通过下标获取list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"two"
LLEN:查看列表的长度 。例:LLEN letter
127.0.0.1:6379> LLEN letter
4
127.0.0.1:6379>
LREM:移除列表中指定的值。 通常都是移除后面PUSH进来的Value
127.0.0.1:6379> LREM list 1 one #移除list集合中指定个数的Value,精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "two"
4) "one"
127.0.0.1:6379> LREM list 1 two
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
LTRIM:删除列表中制定范围以外的元素。例:LTRIM letter 1 3(删除列表中索引为1-3以外的元素)
127.0.0.1:6379> Rpush list "hello"
(integer) 1
127.0.0.1:6379> Rpush list "hello1"
(integer) 2
127.0.0.1:6379> Rpush list "hello2"
(integer) 3
127.0.0.1:6379> Rpush list "hello3"
(integer) 4
127.0.0.1:6379> Ltrim list 1 2 # 通过下标截取指定的长度,这个list已经被改变了(截断了),只剩下截取后的元素!
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "hello1"
2) "hello2"
RPOPLPUSH:移除列表的最后一个元素,将他移动到新的列表中。
127.0.0.1:6379> Rpush list "hello"
(integer) 1
127.0.0.1:6379> Rpush list "hello1"
(integer) 2
127.0.0.1:6379> Rpush list "hello2"
(integer) 3
127.0.0.1:6379> Rpush list "hello3"
(integer) 4
127.0.0.1:6379> RPOPLPUSH list mylist # 移除列表的最后一个元素,并将他移动到新的列表中!
"hello3"
127.0.0.1:6379> LRANGE list 0 -1 # 查看原来的列表
1) "hello"
2) "hello1"
3) "hello2"
127.0.0.1:6379> LRANGE mylist 0 -1 #查看目标列表中,确实存在该值!
1) "hello3"
LSET:将列表中指定下标的值替换成另外一个值,更新操作。
127.0.0.1:6379> EXISTS list # 判断这个列表是否存在
(integer) 0
127.0.0.1:6379> LSET list 0 item # 如果不存在列表,更新就会报错
(error) ERR no such key
127.0.0.1:6379> LPUSH list value1
(integer) 1
127.0.0.1:6379> LRANGE list 0 0
1) "value1"
127.0.0.1:6379> LSET list 0 item # 如果存在,就会更新当前下标的值
OK
127.0.0.1:6379> LRANGE list 0 0
1) "item"
127.0.0.1:6379> LSET list 1 hello # 如果不存在,则会报错!
(error) ERR index out of range
LINSERT: 将某个具体的value插入到列表中某个元素的前面或者后面。
127.0.0.1:6379> RPUSH list "hello"
(integer) 1
127.0.0.1:6379> RPUSH list "world"
(integer) 2
127.0.0.1:6379> LINSERT list before "world" "other" # 将other插入到world的前面(before)
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LINSERT list after world new # 将new插入到world的后面(new)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"
总结 :
- 实际上是一个链表,before Node after,left,right都可以插入值
- 如果key不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在!
- 在两边插入或者修改值,效率最高!中间元素,相对来说效率会低一点~
Set 集合命令(无序集合且元素不可重复,set相关的命令都是以 “ S ” 开头)
SADD:表示向set中添加元素。例: SADD course Redis Java Linux Redis
SMEMBERS: 查看集合中的元素。例:SMEMBERS course
SISMEMBER:判断元素是否在集合中。例:SISMEMBER courser Redis(输出是1表示在集合中,输出为0表示不在集合中)
127.0.0.1:6379> SADD list hello
(integer) 1
127.0.0.1:6379> SADD list world
(integer) 1
127.0.0.1:6379> SADD list redis
(integer) 1
127.0.0.1:6379> SMEMBERS list #查看指定set中的所有值
1) "hello"
2) "world"
3) "redis"
127.0.0.1:6379>
127.0.0.1:6379> SISMEMBER list redis # 判断一个值是不是在set集合中!
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> SISMEMBER list nihao
(integer) 0
SREM:移除set集合中指定的元素。
127.0.0.1:6379> SREM list hello
(integer) 1
127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"
SCARD:获取set集合中的个数。
127.0.0.1:6379> SCARD list
(integer) 3
SRANDMEMBER: 随机从set集合中抽出一个元素。
127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"
127.0.0.1:6379> SRANDMEMBER list # 随机抽选出一个元素
"redis"
127.0.0.1:6379> SRANDMEMBER list
"world"
127.0.0.1:6379> SRANDMEMBER list 2 # 随机抽选出制定个数的元素
1) "world"
2) "redis"
SPOP:随机删除一些set集合中的元素!
127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"
3) "Java"
4) "Linux"
127.0.0.1:6379> SPOP list # 随机移除一些set集合中的元素!
"world"
127.0.0.1:6379> SPOP list
"Java"
127.0.0.1:6379> SMEMBERS list
1) "redis"
2) "Linux"
SMOVE:将set集合一个指定的值,移动到另一个set集合中!
127.0.0.1:6379> SADD list hello
(integer) 1
127.0.0.1:6379> SADD list world
(integer) 1
127.0.0.1:6379> SADD list redis
(integer) 1
127.0.0.1:6379> SMEMBERS list
1) "hello"
2) "world"
3) "redis"
127.0.0.1:6379> SADD list2 newlist
(integer) 1
127.0.0.1:6379> SMEMBERS list2
1) "newlist"
127.0.0.1:6379> SMOVE list list2 world # 将list中world的值移动到list2集合中
(integer) 1
127.0.0.1:6379> SMEMBERS list2
1) "newlist"
2) "world"
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) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2 # 交集 共同好友可以这样实现
1) "c"
127.0.0.1:6379> SUNION key1 key2 # 并集
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
SortedSet(ZSet)
有序集合 每个元素都会关联一个浮点类型的分数,然后按照这个分数来对集合中的元素进行从小到大的排序,元素是唯一的但是分数是可以重复的,有序集合的相关命令都是以 “ Z ” 开头的
ZADD:向有序集合中添加元素。例:ZADD result 680 清华 660 北大 650 复旦 640 浙大(分数在前,元素在后)
ZRANGE:查看集合中的元素。例:ZRANGE result 0 -1 WITHSCORES(WITHSCORES 输出元素的时候输出分数)
127.0.0.1:6379> ZADD salary 2500 xiaohong # 添加三个用户
(integer) 1
127.0.0.1:6379> ZADD salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 2000 xiaoming
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 显示所有用户 从小到大!
1) "xiaoming"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
1) "xiaoming"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 显示全部的用户并且附带成绩
1) "xiaoming"
2) "2000"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores #显示工资小于2500员工的升序排列
1) "xiaoming"
2) "2000"
3) "xiaohong"
4) "2500"
ZSCORE:查看元素的分数
> ZSCORE result 清华
"680"
ZRANK:查看元素从小到大排序后的下标
> ZRANK result 清华
(integer) 3
ZREVRANK:反转。例:ZREVRANK result 清华(查看清华从大到小排序后的下标)
> ZRANK result 清华
(integer) 3
> ZREVRANK result 清华
(integer) 0
Hash(哈希)
(Map集合 key{map},值是一个map集合,适合用来存储对象,相关的命令都是以 “ H ” 开头)
本质和String类型没有太大区别,还是一个简单的key-value
HSET:向哈希中添加一个键值对。
HGET:来获取哈希中某个键值对。
HMSET:设置多个key-value
HMGET:获取多个key
HGETALL:来获取整个哈希中所有的键值对,name是键,hy是值
127.0.0.1:6379> HSET myhash field1 hello # set一个具体的 key-value
(integer) 1
127.0.0.1:6379> HGET myhash field1 #获取一个字段值
"hello"
127.0.0.1:6379> HMSET myhash field1 world field2 redis #set多个key-value
OK
127.0.0.1:6379> HMGET myhash field1 field2 #获取多个字段
1) "world"
2) "redis"
127.0.0.1:6379> HGETALL myhash #获取全部数据
1) "field1"
2) "world"
3) "field2"
4) "redis"
HDEL:删除hash中指定的key字段,对应的value也就消失了
> HDEL person age
(integer) 1
> HGETALL person
1) "name"
2) "hy"
HEXISTS:判断某个键值对是否存在。(1表示存在,0表示不存在)
> HEXISTS person name
(integer) 1
> HEXISTS person age
(integer) 0
HKEYS:获取哈希中的所有字段
HVALS:获取所有的的value
> HKEYS person
1) "name"
HLEN:获取哈希中所有的键值对的数量
> HLEN person
(integer) 1
Stream(消息队列)轻量级的消息队列,相关的命令以 “ S ” 开头
XADD::向Streamm中添加消息。例:XADD hy * course redis( * 表示自动生成一个消息ID 并且会保证生成的ID是递增的 )
回显的信息(1722853636808-0)就是消息的ID
ID的格式是 整数-整数(1-0)1表示时间戳 0表示一个序列号
如果手动指定ID的话,就需要自己来保证这个ID的递增
> XADD hy * courser redis
1722853636808-0
> XADD hy * courser git
"1722853722649-0"
> XADD hy * courser docker
"1722853727918-0"
SLEN:查看Stream中消息的数量。例:XLEN hy
> XLEN hy
(integer) 3
XRANGE :查看Stream中的消息和详细内容。例:XRANGE hy - +(开始和结束可以使用 - +表示所有的消息)
> XRANGE hy - +
1) 1) "1722853636808-0"
2) 1) "courser"
2) "redis"
2) 1) "1722853722649-0"
2) 1) "courser"
2) "git"
3) 1) "1722853727918-0"
2) 1) "courser"
2) "docker"
XDEL:删除消息。例:XDEL hy 1722853727918-0(对应的是消息的ID)
也可以通过XTRIM命令来执行。例:XTRIM hy MAXLEN 0(MAXLENS 0 表示删除所有的消息)
> XDEL hy 1722853727918-0
(integer) 1
> XRANGE hy - +
1) 1) "1722853636808-0"
2) 1) "courser"
2) "redis"
2) 1) "1722853722649-0"
2) 1) "courser"
2) "git"
> XTRIM hy MAXLEN 0
(integer) 2
> XRANGE hy - +
(empty list or set)
SREAD:读取消息。例:SREAD COUNT 2 BLOCK 1000 STREAMS huang 0
(COUNT 2表示读取两条消息,BLOCK 1000---如果没有就阻塞1000毫秒,STREAMS后面加上消息队列的名称)
( 0表示下标 从第一位开始读取,如果比消息队列中下标大 就会阻塞1秒。获取从此刻开始以后的最新消息可以将0改为$)可以重复读取
> XADD huang 1-0 courses git
"1-0"
> XADD huang 2-0 courses docker
"2-0"
> XADD huang 3-0 courses redis
"3-0"
> XREAD COUNT 2 BLOCK 1000 STREAMS huang 0
1) 1) "huang"
2) 1) 1) "1-0"
2) 1) "courses"
2) "git"
2) 1) "2-0"
2) 1) "courses"
2) "docker"
XGROUP:创建消费组。例:XGROUP CREATE hy(消息的名称)group1(组的名称)0(ID)创建了一个名为group1的消费者组
> XGROUP CREATE hy group1 0
"OK"
XINFO GROUPS:查看消费者组的信息。例:XINFO GROUPS hy(是键值不是组的名称)
> XINFO GROUPS hy
1) 1) "name"
2) "group1"
3) "consumers"
4) "0"
5) "pending"
6) "0"
7) "last-delivered-id"
8) "0-0"
XGROUP CREATECONSUMER:创建消费者。例:XGROUP CREATECONSUMER hello(消息的名称)group1(组的名称)consumer1(消费者的名称)
三种特殊数据类型
geospatial 地理位置
朋友的定位,附近的人,打车距离计算
GEOADD:添加地理位置。(两级(南极与北极)无法直接添加,一般会下载城市数据,直接通过java程序一次性导入!)
参数:key 值(经度、纬度、名称)
有效的经度是-180到180度,有效的纬度是-85.05112878到85.05112878
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijin
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.60 29.53 chongqi
(integer) 1
127.0.0.1:6379> GEOADD china:city 114.05 22.52 shengzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 108.96 34.26 xian
(integer) 1
GEOPOS:获取指定的城市的经度和纬度。
127.0.0.1:6379> GEOPOS china:city beijin
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS china:city shanghai xian
1) 1) "121.47000163793563843"
2) "31.22999903975783553"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
GEODIST:返回来两个给定位置之间的距离。
- m表示单位为m
- km表示单位为千米
- mi表示单位为英里
- ft表示单位为英尺
127.0.0.1:6379> GEODIST china:city beijin xian # 查看北京到西安的直线距离
"910056.5237"
127.0.0.1:6379> GEODIST china:city beijin xian km # 查看北京到西安的直线距离 单位为km
"910.0565"
127.0.0.1:6379> GEODIST china:city beijin shanghai
"1067378.7564"
127.0.0.1:6379> GEODIST china:city beijin shanghai km
"1067.3788"
附近的人(获取所有附近的人的地址,定位!)通过半径来查询!
所有的数据应该录入china:city,才会让结果更加精确!
GEORADIUS:以给定的经纬度为中心,找出某一半径内的元素
# 以110 30 这个经纬度为中心,寻找房源1000km内的城市
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
1) "chongqi"
2) "xian"
# 显示到中心距离的位置
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist
1) 1) "chongqi"
2) "332.3998"
2) 1) "xian"
2) "483.8340"
# 显示出他人的定位信息(经纬度)
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord
1) 1) "chongqi"
2) 1) "106.60000115633010864"
2) "29.52999957900659211"
2) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
# 筛选出指定的结果!
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1
1) 1) "chongqi"
2) "332.3998"
3) 1) "106.60000115633010864"
2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 2
1) 1) "chongqi"
2) "332.3998"
3) 1) "106.60000115633010864"
2) "29.52999957900659211"
2) 1) "xian"
2) "483.8340"
3) 1) "108.96000176668167114"
2) "34.25999964418929977"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 3
1) 1) "chongqi"
2) "332.3998"
3) 1) "106.60000115633010864"
2) "29.52999957900659211"
2) 1) "xian"
2) "483.8340"
3) 1) "108.96000176668167114"
2) "34.25999964418929977"
GEORADIUSBYMEMBER:找出位于指定元素周围的其他元素
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijin 1000 km
1) "beijin"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
GEOHASH:返回一个或多个位置元素的Geohash表示。(将返回11个字符的Geohash字符串!)
将二维的经纬度转换为一维的字符串,如果两个字符串越接近,两个距离就越近!
127.0.0.1:6379> GEOHASH china:city beijin shanghai
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
127.0.0.1:6379> GEOHASH china:city beijin xian
1) "wx4fbxxfke0"
2) "wqj6zky6bn0"
GEO底层的实现原理其实就是ZSet!可以使用ZSet命令来操作geo!
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijin"
127.0.0.1:6379> ZREM china:city beijin
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
HyperLogLog
基数统计的算法
优点:占用的内存是固定的,2^64不同的元素的基数,只需要12kb的内存!如果要从内存角度来比较的话Hyperloglog首选!
A:{1,2,4,5,7,6}、B:{2,5,6} 基数(不重复的元素的个数)= 3,可以接受误差!
网页的UV(一个人访问一个网址多次,但是还是算作一个人)
传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断
这个方式如果保存大量的用户id,就会比较麻烦!目的是为了计数,而不是保存用户的id
0.81%错误率! 统计UV任务,可以忽略不计!
127.0.0.1:6379> PFADD mykey a b c d e f g h i j # 创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey # 统计mykey的元素基数数量
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m # 创建第二组元素 mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 # 合并两组mykey mykey2 => mykey3 并集
OK
127.0.0.1:6379> PFCOUNT mykey3 # 查看并集的数量
(integer) 15
如果允许容错,可以使用Hyperloglog!如果不允许容错,可以使用set或者自己的数据类型即可!
Bitmaps
位储存
统计用户信息,活跃,不活跃!登录,为登录。两个状态的,都可以使用Bitmaps
Bitmaps位图,数据结构!都是操作二进制位来进行记录,只有 0 和 1 两个状态
使用Bitmaps 来记录 周一到周日的打卡记录!SETBIT
127.0.0.1:6379> SETBIT sign 0 1 # 0 代表星期一 1 代表已打卡
(integer) 0
127.0.0.1:6379> SETBIT sign 1 0 # 1 代表星期二 0 代表未打卡
(integer) 0
127.0.0.1:6379> SETBIT sign 2 0
(integer) 0
127.0.0.1:6379> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379> SETBIT sign 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign 5 0
(integer) 0
127.0.0.1:6379> SETBIT sign 6 0
(integer) 0
查询某一天是否有打卡!GETBIT
127.0.0.1:6379> GETBIT sign 0 # 查看星期一是否打卡!输出1为已打卡
(integer) 1
127.0.0.1:6379> GETBIT sign 1 # 查看星期二是否打卡!输出0为未打卡
(integer) 0
统计打卡次数!BITCOUNT
127.0.0.1:6379> BITCOUNT sign # 统计打卡一个星期内的打卡次数
(integer) 3
事务
Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性,顺序性,排他性!执行一系列的命令
------ 队列 set set set 队列 ------
Redis事务没有隔离级别的概念!
所有的命令在事务中,并没有直接执行!只有发起执行命令的时候才会执行!Exec!!!
Redis单条命令是保证原子性的,但是事务是不保证原子性的!
redis的事务:
- 开启事务(MULTI)
- 命令入列(……)
- 执行事务(EXEC)
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
2) OK
3) "v2"
4) OK
DISCARD:取消事务
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> DISCARD # 取消事务
OK
127.0.0.1:6379> get k4 # 事务队列中的命令都不会被执行!
(nil)
编译型异常(代码有问题!命令有错误!),事务中所有的指令都不会被执行!
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3 # 错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务报错!
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4 #所有的命令都不会被执行!
(nil)
运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incr k1 # 会执行的时候失败!
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range # 虽然第一条命令,但是依旧正常执行成功!
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
WATCH:监控! watch加锁 unwatch解锁
悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会加锁!
乐观锁:
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下在此期间是否有人修改过数据。
获取version
更新的时候比较version
Redis监控测试
# 正常执行成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money # 监视money对象
OK
127.0.0.1:6379> multi # 事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
测试多线程修改值,使用watch可以当做redis的乐观锁的操作!
127.0.0.1:6379> watch money # 监视 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED
# 执行之前,另外一个线程修改了money的值,这个时候就会导致事务执行失败!
127.0.0.1:6379(TX)> exec
(nil)
如果修改失败,获取最新的值即可!
27.0.0.1:6379> unwatch # 如果发现事务执行失败,就先解锁
OK
127.0.0.1:6379> watch money # 获取最新的值,再次监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED
# 比对监视的值是否发生了变化,如果没有发生变化,那么可以执行成功,否则执行失败
127.0.0.1:6379(TX)> exec
1) (integer) 990
2) (integer) 30
标签:127.0,0.1,list,Redis,笔记,6379,set,integer
From: https://blog.csdn.net/m0_58533479/article/details/140880452