一.五大数据类型
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)即集群搭建。
1.1 Redis-Key
1、常用命令
# 连接redis客户端
[root@iZuf67rdcsn46d295zbgomZ ~]# redis-cli -p 6379
# 测试是否能拼通
127.0.0.1:6379> ping
PONG
# 清空所有数据
127.0.0.1:6379> flushall
OK
# 查看当前数据库中的所有的key
127.0.0.1:6379> keys *
(empty array)
2、set 设置key
############################### set 设置key值 ###################################
# 设置key
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> keys *
1 ) "name"
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> keys *
1 ) "age"
2 ) "name"
3、EXISTS 判断当前的key是否存在
########################## EXISTS 判断当前的key是否存在 ############################
# 判断当前的key是否存在
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
4、move 移动key
########################### move 移动key ##################################
# 移动当前的key至其它数据库
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> EXISTS name
(integer) 0
# 切换数据库
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
# 清除屏幕
127.0.0.1:6379> clear
# 切换数据库
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> keys *
1) "age"
# 设置值
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"lisi"
5、EXPIRE 设置key的过期时间
########################### EXPIRE 设置key的过期时间 ##############################
# 设置key的过期时间,单位是秒(设置热点数据,一定时间内过期,例如单点登录)
127.0.0.1:6379> EXPIRE name 10
# 设置成功
(integer) 1
# 查看当前key的剩余时间
127.0.0.1:6379> ttl name
(integer) 4
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
# key已过期
(integer) -2
# 获取key
127.0.0.1:6379> get name
# 数据库中没有此key
(nil)
6、del 移除key
############################### del 移除key #################################
# 查看所有的key
127.0.0.1:6379> keys *
1) "age"
# 移除 key
127.0.0.1:6379> del age
# 移除成功
(integer) 1
127.0.0.1:6379> keys *
(empty array)
7、type 查看当前key的类型
############################## type 查看当前key的类型 #################################
# 查看所有的key
127.0.0.1:6379> keys *
(empty array)
# 设置值
127.0.0.1:6379> set name zs
OK
127.0.0.1:6379> set age 1
OK
# 查看当前key的类型
127.0.0.1:6379> type name
# 字符串类型
string
127.0.0.1:6379> type age
string
可以参考官网上的常用命令:
1.2 String 字符串类型
1、set设置值 get获取值 EXISTS判断key是否存在
################################### set 设置值 #######################################
# 设置值
127.0.0.1:6379> set key1 v1
OK
################################### get 设置值 ####################################
# 获得值
127.0.0.1:6379> get key1
"v1"
############################### keys 获得所有的key #################################
# 获得所有的key
127.0.0.1:6379> keys *
1 ) "key1"
############################### EXISTS 判断key是否存在 ##############################
# 判断某一个key是否存在
127.0.0.1:6379> EXISTS key1
(integer) 1
2、APPEND追加字符串 STRLEN获取字符串的长度
############################# APPEND 追加字符串 #################################
# 追加字符串,如果当前key不存在,就相当于set key
127.0.0.1:6379> APPEND key1 "hello"
(integer) 7
# 获取值
127.0.0.1:6379> get key1
"v1hello"
############################# STRLEN 获取字符串的长度 ###############################
# 获取字符串的长度
127.0.0.1:6379> STRLEN key1
(integer) 7
# 追加字符串
127.0.0.1:6379> APPEND key1 ",world"
(integer) 13
# 获取值
127.0.0.1:6379> get key1
"v1hello,world"
# 获取字符串的长度
127.0.0.1:6379> strlen key1
(integer) 13
3、incr值自增 decr值自减 INCRBY/DECRBY 设置步长,指定增减量
################################# 设置值 #######################################
# 初始浏览量为 0
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
################################## incr 值自增 ##################################
# 类似于 i++ , 步长 i+=
# 自增 1 浏览量变为 1
127.0.0.1:6379> incr views
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
################################## decr 值自减 ####################################
# 自减 1 浏览量-1
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
########################### INCRBY/DECRBY 设置步长,指定增减量 ##########################
# 可以设置步长,指定增量
127.0.0.1:6379> INCRBY views 10
(integer) 9
127.0.0.1:6379> INCRBY views 10
(integer) 19
# 可以设置步长,指定减量
127.0.0.1:6379> DECRBY views 5
(integer) 14
4、GETRANGE 获取指定范围的字符串
##############################GETRANGE 获取指定范围的字符串#################################
# 获取所有key
127.0.0.1:6379> keys *
(empty array)
# 设置值
127.0.0.1:6379> set key1 "hello world"
OK
# 获取值
127.0.0.1:6379> get key1
"hello world"
# 查看字符串的长度
127.0.0.1:6379> strlen key1
(integer) 11
# 截取指定范围的字符串( 闭区间[0,3] )
127.0.0.1:6379> getrange key1 0 3
"hell"
# 截取指定范围的字符串( 闭区间[0,-1] )当第二个参数设置为-1时,即截取全部字符串,与get key是一样效果
127.0.0.1:6379> getrange key1 0 -1
"hello world"
5、SETRANGE 字符串替换
############################# SETRANGE 字符串替换 ################################# # 设置值 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 (integer) 7 127.0.0.1:6379> get key2 "axxdefg"
6、setex (set with expire) 设置过期时间
setnx (set if not exist) 不存在再设置(在分布式锁中会常常使用)
####################### 设置过期时间 setex (set with expire) ########################## # 获取所有key 127.0.0.1:6379> keys * (empty array) # 设置key1 的值为 hello,30秒后过期 127.0.0.1:6379> setex key1 30 "hello" OK # 查看当前key的剩余时间 127.0.0.1:6379> ttl key1 (integer) 25 # 获取key1的值 127.0.0.1:6379> get key1 "hello" ####################### 不存在再设置 setnx (set if not exist) ######################## # 如果key2不存在,创建key2 127.0.0.1:6379> setnx key2 "world" (integer) 1 127.0.0.1:6379> keys * 1) "key2" # 如果key2存在,创建失败 127.0.0.1:6379> setnx key2 "redis" (integer) 0 127.0.0.1:6379> get key2 "world"
7、mset批量设置值 mget批量获取值
############################## mset和mget 批量操作 #################################### # 同时设置多个值 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" ######################### msetnx 批量为不存在的元素设置值 ################################# # 同时为不存在的再设置值,msetnx是一个原子性的操作,要么一起成功,要么一起失败 127.0.0.1:6379> msetnx k1 v1 k4 v4 # k1和k4皆设置失败 (integer) 0 127.0.0.1:6379> keys * 1) "k2" 2) "k3" 3) "k1"
8、设置对象
############################## 对象 ################################### # 第一种方式:用json字符串保存一个对象信息 user:{id} {field:value,field:value} # 设置user:1对象的值 , 若设置同名的对象,则会发生覆盖 127.0.0.1:6379> set user:1 {name:zs,age:10} OK # 获取user:1对象的值 127.0.0.1:6379> get user:1 "{name:zs,age:10}" # 第二种方式:批量分别设置对象的值的方式 user:{id}:{field} {value} # 同时设置user:2:name 和 user:2:age 127.0.0.1:6379> mset user:2:name lisi user:2:age 20 OK # 同时获取user:2:name 和 user:2:age 127.0.0.1:6379> mget user:2:name user:2:age 1) "lisi" 2) "20"
9、getset 获取旧值并设置新值
######################### getset 获取旧值并设置新值 ############################ # 如果不存在值,则返回 nil 127.0.0.1:6379> getset key1 hello (nil) # 如果存在值,获取原来的值,并设置新的值 127.0.0.1:6379> getset key1 world "hello" # 获取值,已经是最新的值 127.0.0.1:6379> get key1 "world"
10、使用场景
value除了是我们的字符串还可以是我们的数字
计数器 例如:INCRBY 统计多单位的数量 例如:批量对象属性的值存储 user:{id}:{field} {value} 粉丝数 对象缓存存储
6.3 List 列表
在redis里面,我们可以把list当作栈、队列、阻塞队列。所有的list命令都是用 L 开头的,Redis不区分大小命令。
1、LPUSH左边添加值 RPUSH右边添加值
# 清空数据库 127.0.0.1:6379> flushdb OK # 查看所有key 127.0.0.1:6379> keys * (empty array) ############################# LPUSH 左边添加值 ########################## # 将一个值或者多个值,插入到列表头部 (左) 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 ############################# LRANGE 闭区间获取值 ########################## # 通过区间获取list具体的值,设置为-1代表取到最后 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" # 通过区间获取list具体的值 [0,1]闭区间 127.0.0.1:6379> LRANGE list 0 1 1) "three" 2) "two" ############################# RPUSH 右边添加值 ########################## # 将一个值或者多个值,插入到列表位部 (右) 127.0.0.1:6379> RPUSH list right (integer) 4 # 通过区间获取具体的值,设置为-1代表取到最后 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" 4) "right"
2、LPOP移除并返回最左边元素 RPOP移除并返回最右边元素
# 查询list列表中的所有元素 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" 4) "right" ############################ LPOP 移除并返回最左边元素 ############################ # 移除list的第一个元素 127.0.0.1:6379> LPOP list "three" ############################ RPOP 移除并返回最右边元素 ############################ # 移除list的最后一个元素 127.0.0.1:6379> RPOP list "right" # 查询list列表中的所有元素 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "one"
3、Lindex 通过下标获取值
############################# Lindex 通过下标获取值 ############################## # 查询list列表中的所有元素 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "one" # 通过下标获得 list 中的某一个值 127.0.0.1:6379> lindex list 0 "two" 127.0.0.1:6379> lindex list 1 "one"
4、Llen 返回列表的长度
############################## Llen 返回列表的长度 ################################# # 清空当前数据库 127.0.0.1:6379> flushdb OK # 给list列表传入值 127.0.0.1:6379> LPUSH list 111 (integer) 1 127.0.0.1:6379> LPUSH list 222 (integer) 2 127.0.0.1:6379> LPUSH list 333 (integer) 3 # 返回list列表的长度 127.0.0.1:6379> LLEN list (integer) 3
5、Lrem 移除指定的值
############################## Lrem 移除指定的值 ############################### # 给list列表中存入重复值 127.0.0.1:6379> LPUSH list 333 (integer) 4 # 查看list列表中所有值,列表中允许存放同一值 127.0.0.1:6379> LRANGE list 0 -1 1) "333" 2) "333" 3) "222" 4) "111" # 移除list集合中指定 个数 的 value,精确匹配 # 移除一个"111"的值 127.0.0.1:6379> LREM list 1 111 (integer) 1 127.0.0.1:6379> LRANGE list 0 -1 1) "333" 2) "333" 3) "222" # 移除两个"333"的值 127.0.0.1:6379> LREM list 2 333 (integer) 2 # 查看list列表中所有值 127.0.0.1:6379> LRANGE list 0 -1 1) "222"
6、Ltrim 截取
################################ Ltrim 截取 ###################################### # 清空当前数据库 127.0.0.1:6379> flushdb OK # 查询所有key 127.0.0.1:6379> keys * (empty array) # 向list列表右边添加值 127.0.0.1:6379> RPUSH list aaa (integer) 1 127.0.0.1:6379> RPUSH list bbb (integer) 2 127.0.0.1:6379> RPUSH list ccc (integer) 3 127.0.0.1:6379> RPUSH list ddd (integer) 4 127.0.0.1:6379> LRANGE list 0 -1 1) "aaa" 2) "bbb" 3) "ccc" 4) "ddd" # 通过下标截取指定的位置(闭区间),这个list已经被改变了,截断了只剩下截取的元素 127.0.0.1:6379> LTRIM list 1 2 OK 127.0.0.1:6379> LRANGE list 0 -1 1) "bbb" 2) "ccc"
7、 rpoplpush 移除原列表的最右边元素,并添加到新列表的最左边
######################### rpoplpush 原列表 目标列表 ######################### # 清空当前数据库 127.0.0.1:6379> flushdb OK # 给mylist列表最右边添加值 127.0.0.1:6379> RPUSH mylist aaa (integer) 1 127.0.0.1:6379> RPUSH mylist bbb (integer) 2 127.0.0.1:6379> RPUSH mylist ccc (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "aaa" 2) "bbb" 3) "ccc" # 移除列表的最右边元素,将他移动到新列表的最左边 127.0.0.1:6379> RPOPLPUSH mylist myother "ccc" # 查看原列表中的元素 127.0.0.1:6379> LRANGE mylist 0 -1 1) "aaa" 2) "bbb" # 查看目标列表中的元素 127.0.0.1:6379> LRANGE myother 0 -1 1) "ccc" # 移除列表的最右边元素,将他移动到新列表的最左边 127.0.0.1:6379> RPOPLPUSH mylist myother "bbb" # 查看原列表中的元素 127.0.0.1:6379> LRANGE mylist 0 -1 1) "aaa" # 查看原列表中的元素 127.0.0.1:6379> LRANGE myother 0 -1 1) "bbb" 2) "ccc"
8、Lset 更新当前下标的值,若当前列表不存在更新则会报错
################ Lset 将列表中指定下标的值替换为另外一个值,更新操作 #################### # 判断这个列表是否存在 127.0.0.1:6379> EXISTS list (integer) 0 # 如果列表不存在,更新会报错 127.0.0.1:6379> lset list 0 aaa (error) ERR no such key # 先给列表中存入元素 127.0.0.1:6379> lpush list aaa (integer) 1 # 查看列表中所有元素 127.0.0.1:6379> LRANGE list 0 -1 1) "aaa" # 如果列表存在,更新当前下标的值 127.0.0.1:6379> lset list 0 bbb OK 127.0.0.1:6379> LRANGE list 0 -1 1) "bbb" # 如果列表对应下标不存在值,则会报错 127.0.0.1:6379> lset list 1 ccc (error) ERR index out of range
9、Linsert 将某个具体的value插入到列表中某个元素的前面或者后面
############## linsert 将某个具体的value插入到列表中某个元素的前面或者后面 ############## # 清空数据库 127.0.0.1:6379> flushdb OK # 查看所有key 127.0.0.1:6379> keys * (empty array) # 在列表的最右边添加元素 127.0.0.1:6379> rpush list aaa (integer) 1 127.0.0.1:6379> rpush list bbb (integer) 2 127.0.0.1:6379> rpush list bbb (integer) 3 # 查看列表中的所有元素 127.0.0.1:6379> LRANGE list 0 -1 1) "aaa" 2) "bbb" 3) "bbb" # 在指定的列表元素前面添加值 127.0.0.1:6379> LINSERT list before bbb hello (integer) 4 127.0.0.1:6379> LRANGE list 0 -1 1) "aaa" 2) "hello" 3) "bbb" 4) "bbb" # 在指定的列表元素后面添加值 127.0.0.1:6379> LINSERT list after bbb world (integer) 5 127.0.0.1:6379> LRANGE list 0 -1 1) "aaa" 2) "hello" 3) "bbb" 4) "world" 5) "bbb"
10、使用场景
1).List实际上是一个链表,before Node after , left,right 都可以插入值
2).如果key不存在,创建新的链表;如果key存在,新增内容
3).如果移除了所有值,则是空链表,说明不存在了
5).在两边插入或者改动值,效率最高;若是中间元素,相对来说效率会低一点
6).可以使用List实现消息排队、消息队列 (Lpush Rpop)、 栈( Lpush Lpop)
6.4 Set 无序不重复集合
1、sadd 添加元素
#############################sadd 给set集合添加元素 ######################################## # 清空数据库 127.0.0.1:6379> flushall OK # 添加元素 127.0.0.1:6379> sadd myset hello (integer) 1 127.0.0.1:6379> sadd myset redis (integer) 1 127.0.0.1:6379> sadd myset world (integer) 1 # 添加重复元素,返回0代表添加失败 127.0.0.1:6379> sadd myset hello (integer) 0 ########################## SMEMBERS 查看指定set集合的所有值 ########################### # 查看集合中所有值 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" 3) "redis"
2、SISMEMBER 判断某一个值是不是在set集合中
##################### SISMEMBER 判断某一个值是不是在set集合中 ######################## # 判断集合中是否存在某个值,返回1则存在,返回0则不存在 127.0.0.1:6379> SISMEMBER myset hello (integer) 1 127.0.0.1:6379> SISMEMBER myset aaa (integer) 0
4、scard 获取集合中的内容元素个数
######################### scard 获取集合中的内容元素个数 ############################ 127.0.0.1:6379> SCARD myset (integer) 3 127.0.0.1:6379> SADD myset aaa (integer) 1 127.0.0.1:6379> SCARD myset (integer) 4
5、srem 移除set集合中的指定元素
######################### srem 移除set集合中的指定元素 ############################# # 查看集合中所有元素 127.0.0.1:6379> SMEMBERS myset 1) "aaa" 2) "hello" 3) "world" 4) "redis" # 移除set集合中的指定元素 127.0.0.1:6379> srem myset aaa (integer) 1 # 查看集合中所有元素 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" 3) "redis"
6、SRANDMEMBER 随机抽选出一个元素
########################### SRANDMEMBER 随机抽选出一个元素 ######################### # 查看集合中所有元素 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" 3) "redis" # 随机抽选出一个元素 127.0.0.1:6379> SRANDMEMBER myset "hello" 127.0.0.1:6379> SRANDMEMBER myset "redis" # 随机抽选出指定个数的元素 127.0.0.1:6379> SRANDMEMBER myset 2 1) "redis" 2) "world" 127.0.0.1:6379> SRANDMEMBER myset 2 1) "hello" 2) "world"
7、spop 删除key,随机删除key
############################# spop 随机删除key ######################### # 查看集合中所有元素 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" 3) "redis" # 随机弹出key并返回 127.0.0.1:6379> SPOP myset "hello" 127.0.0.1:6379> SPOP myset "world" # 查看集合中所有元素 127.0.0.1:6379> SMEMBERS myset 1) "redis"
8、smove 将一个指定的值,移动到另外一个set集
######################## smove 将一个指定的值,移动到另外一个set集 ##################### # 清空数据库 127.0.0.1:6379> flushdb OK # 给myset集合添加元素 127.0.0.1:6379> sadd myset hello (integer) 1 127.0.0.1:6379> sadd myset redis (integer) 1 127.0.0.1:6379> sadd myset world (integer) 1 # 查看myset集合中的所有元素 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" 3) "redis" # 给myother集合添加元素 127.0.0.1:6379> sadd myother other (integer) 1 # 查看myother集合中的所有元素 127.0.0.1:6379> SMEMBERS myother 1) "other" # 将myset集合中的元素,移动至myother中 127.0.0.1:6379> SMOVE myset myother redis (integer) 1 # 此时myset集合元素少了redis元素 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "world" # 此时myother集合元素多了redis元素 127.0.0.1:6379> SMEMBERS myother 1) "redis" 2) "other"
9、使用场景
例如:微博、B站、抖音都有共同关注这个功能,实际上是数学上交集的概念。
数字集合类:
-
差集 SDIFF
-
交集 SINTER
-
并集 SUNION
# 清空屏幕 127.0.0.1:6379> clear # 清空数据库 127.0.0.1:6379> flushdb OK # set1集合 添加元素 127.0.0.1:6379> sadd set1 a (integer) 1 127.0.0.1:6379> sadd set1 b (integer) 1 127.0.0.1:6379> sadd set1 c (integer) 1 # set2集合 添加元素 127.0.0.1:6379> sadd set2 c (integer) 1 127.0.0.1:6379> sadd set2 d (integer) 1 127.0.0.1:6379> sadd set2 e (integer) 1 # 查看set1集合元素 127.0.0.1:6379> SMEMBERS set1 1) "c" 2) "a" 3) "b" # 查看set2集合元素 127.0.0.1:6379> SMEMBERS set2 1) "d" 2) "e" 3) "c" # 差集:以set1为主,查看与set2集合不同的元素 127.0.0.1:6379> SDIFF set1 set2 1) "a" 2) "b" # 交集:查看集合set1和set2的共同元素,例如共同好友就可以这样实现 127.0.0.1:6379> SINTER set1 set2 1) "c" # 并集:查看集合set1和set2的所有元素 127.0.0.1:6379> SUNION set1 set2 1) "a" 2) "c" 3) "b" 4) "d" 5) "e"
使用场景:例如微博,A用户将所有关注的人放在一个set集合中,将它的粉丝也放在一个set集合中。其中共同关注,共同爱好,二度好友,推荐好友(六度分割理论)
6.5 Hash 哈希
类似于map集合,本质和String类型没有太大区别,还是一个简单的key-value。
1、hset设置值 hget获取值
############################## hset设置值 hget获取值 ########################### # hset设置值 127.0.0.1:6379> hset myhash f1 hello (integer) 1 127.0.0.1:6379> hset myhash f2 world (integer) 1 127.0.0.1:6379> hset myhash f3 redis (integer) 1 # hget获取值 127.0.0.1:6379> hget myhash f2 "world"
2、hmset批量设置值 hmget批量获取值
########################## hmset批量设置值 hmget批量获取值 ######################## # hmset批量设置值 127.0.0.1:6379> hmset myhash f1 aaa f2 bbb f3 ccc OK # hmget批量获取值 127.0.0.1:6379> hmget myhash f1 f2 f3 1) "aaa" 2) "bbb" 3) "ccc"
3、hgetall 获取全部的数据
############################ hgetall 获取全部的数据 ############################### # hset设置值,若key存在则发生覆盖 127.0.0.1:6379> hset myhash f1 zhangsan (integer) 0 # 获取全部数据 127.0.0.1:6379> hgetall myhash 1) "f1" 2) "zhangsan" 3) "f2" 4) "bbb" 5) "f3" 6) "ccc" # hset设置值,若key不存在则直接存入 127.0.0.1:6379> hset myhash f4 ddd (integer) 1 # 获取全部数据 127.0.0.1:6379> hgetall myhash 1) "f1" 2) "zhangsan" 3) "f2" 4) "bbb" 5) "f3" 6) "ccc" 7) "f4" 8) "ddd"
4、hdel 删除hash指定key字段,对应的value值也就消失
#################### hdel 删除hash指定key字段,对应的value值也就消失 ################# # 删除hash的指定key,值也一并删除 127.0.0.1:6379> hdel myhash f1 (integer) 1 # 获取全部数据 127.0.0.1:6379> hgetall myhash 1) "f2" 2) "bbb" 3) "f3" 4) "ccc" 5) "f4" 6) "ddd"
5、hlen 获取hash表的字段数量
############################ hlen 获取hash表的字段数量 ############################### # 查看hash中的键值对数量 127.0.0.1:6379> hlen myhash (integer) 3
6、HEXISTS 判断hash中指定字段是否存在
######################### HEXISTS 判断hash中指定字段是否存在 ########################## # HEXISTS判断hash中是否存在指定的key,不存在则返回0 127.0.0.1:6379> HEXISTS myhash f1 (integer) 0 # HEXISTS判断hash中是否存在指定的key,存在则返回1 127.0.0.1:6379> HEXISTS myhash f2 (integer) 1
7、hkeys只获得所有field,hvals只获得所有value
############################## hkeys 只获得所有键key ############################### 127.0.0.1:6379> hkeys myhash 1) "f2" 2) "f3" 3) "f4" ############################## hvals 只获得所有值value ################################ 127.0.0.1:6379> hvals myhash 1) "bbb" 2) "ccc" 3) "ddd"
8、hincrby 设置增量,若是正数则增加,若是负数则减少
# 设置值 127.0.0.1:6379> hset myhash f5 5 (integer) 1 # 获取值 127.0.0.1:6379> hget myhash f5 "5" # 设置正数,给指定属性自增值 127.0.0.1:6379> HINCRBY myhash f5 2 (integer) 7 127.0.0.1:6379> hget myhash f5 "7" # 设置负数,给指定属性自减值 127.0.0.1:6379> HINCRBY myhash f5 -2 (integer) 5 127.0.0.1:6379> hget myhash f5 "5"
9、hsetnx 设置值时,若key已存在则失败返回0,不存在则成功返回1
# 设置值时,若key不存在则成功返回1 127.0.0.1:6379> hsetnx myhash f6 aaa (integer) 1 127.0.0.1:6379> hget myhash f6 "aaa" # 设置值时,若key已存在则失败返回0 127.0.0.1:6379> HSETNX myhash f6 bbb (integer) 0 127.0.0.1:6379> hget myhash f6 "aaa"
10、使用场景
hash最多的应用是存储变更的数据,例如将user作为键,name age作为值进行存储,尤其是是用户信息之类的,经常变动的信息。hash 更适合于对象的存储,String更加适合字符串存储。
# 清空数据库 127.0.0.1:6379> flushdb OK # 设置user对象的单个属性的值 127.0.0.1:6379> hset user:1 name zs (integer) 1 # 获取user对象的单个属性的值 127.0.0.1:6379> hget user:1 name "zs" # 批量设置user对象的多个属性的值 127.0.0.1:6379> hmset user:2 name lisi age 10 OK # 批量获取user对象的多个属性的值 127.0.0.1:6379> hmget user:2 name age 1) "lisi" 2) "10"
6.6 Zset 有序集合
在set的基础上,增加了一个标志,此标志可以让值进行排序 ,语法: zadd key score member
1、zadd 添加 zrange 查看
# 添加单个元素 127.0.0.1:6379> zadd myzset 1 one (integer) 1 127.0.0.1:6379> zadd myzset 2 two (integer) 1 127.0.0.1:6379> zadd myzset 3 three (integer) 1 # 添加多个元素 127.0.0.1:6379> zadd myzset 4 four 5 five (integer) 2 # 查看指定下标范围的元素 127.0.0.1:6379> zrange myzset 0 -1 1) "one" 2) "two" 3) "three" 4) "four" 5) "five"
2、ZRANGEBYSCORE 实现升序 ZREVRANGEBYSCORE 实现降序
# 清空数据库 127.0.0.1:6379> flushdb OK # 添加元素 127.0.0.1:6379> zadd salary 2000 zs (integer) 1 127.0.0.1:6379> zadd salary 3000 lisi (integer) 1 127.0.0.1:6379> zadd salary 1500 wang (integer) 1 # 根据salary字段升序排列 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf 1) "wang" 2) "zs" 3) "lisi" # 根据salary字段降序排列 127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf 1) "lisi" 2) "zs" 3) "wang" # 根据salary字段升序排列,显示全部信息(包括名称、薪资) 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores 1) "wang" 2) "1500" 3) "zs" 4) "2000" 5) "lisi" 6) "3000" # 根据salary字段降序排列,显示全部信息(包括名称、薪资) 127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf withscores 1) "lisi" 2) "3000" 3) "zs" 4) "2000" 5) "wang" 6) "1500" # 根据salary字段升序排列,按照指定范围,显示全部信息(包括名称、薪资) 127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores 1) "wang" 2) "1500" 3) "zs" 4) "2000"
3、zrem 移除
# 查看指定下标范围的元素 127.0.0.1:6379> ZRANGE salary 0 -1 1) "wang" 2) "zs" 3) "lisi" # 移除元素 127.0.0.1:6379> zrem salary zs (integer) 1 127.0.0.1:6379> ZRANGE salary 0 -1 1) "wang" 2) "lisi"
4、zcard 获取有序集合中元素的个数
# 获取有序集合中元素的个数 127.0.0.1:6379> zcard salary (integer) 2
5、zcount 获取集合中指定区间的元素个数
# 获取指定区间的元素个数 127.0.0.1:6379> zcount salary 500 1500 (integer) 1 127.0.0.1:6379> zcount salary 500 3000 (integer) 2
6、使用场景
zset 即是对set排序
1). 可以存储班级成绩表、工资表排序等
2). 带权重进行判断:普通消息 1 ,重要消息 2
3). 实现排行榜应用:将播放量或评分放进有序集合中进行遍历, 或者取TopN测试
七.三种特殊数据类型
7.1 Geospatial 地理位置
思考:朋友的定位,附近的人,打车距离计算如何实现?
解决:Redis 的 Geo 在Redis3.2 版本就推出了,这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人。
参考:城市经度纬度查询网站,可以查询一些测试数据:http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/
相关六个命令: - GEOADD - GEODIST - GEOHASH - GEOPOS - GEORADIUS - GEORADIUSBYMEMBER
参考文档:https://www.redis.net.cn/order/3685.html
1、GEOADD 添加地理位置
语法:
# 将指定的地理空间位置(经度、纬度、名称)添加到指定的key中 GEOADD key longitude经度 latitude纬度 member地理名 [longitude latitude member ...]
规则:
# 两级无法直接添加,一般开发过程中会下载城市数据,直接通过java程序一次性导入。 # 有效的经度从-180度到180度,有效的纬度从-85.05112878度到85.05112878度,当坐标位置超出上述指定范围时,该命令将会返回一个错误。 #如下: 127.0.0.1:6379> geoadd china:city 39.90 116.40 beijing (error) ERR invalid longitude,latitude pair 39 .900000,116.400000
案例:
# GEOADD 添加地理位置(经度、纬度、名称) 127.0.0.1:6379> geoadd china:city 116.405285 39.90498 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 114.298572 30.584355 wuhan (integer) 1 127.0.0.1:6379> geoadd china:city 118.11022 24.490474 xiamen (integer) 1 127.0.0.1:6379> geoadd china:city 118.767413 32.04154 nanjing (integer) 1 127.0.0.1:6379> geoadd china:city 106.504962 29.533155 chongqing (integer) 1 127.0.0.1:6379> geoadd china:city 114.177314 22.266416 xianggang 113.549134 22.19875 aomen (integer) 2
2、GEOPOS 获得当前定位,即坐标值
语法:
# 从key里返回所有给定位置元素的位置(经度和纬度) GEOPOS key member [member ...]
规则:
# GEOPOS 命令返回一个数组,数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。 # 当给定的位置元素不存在时,对应的数组项为空值。
案例:
# GEOPOS 获得指定城市的经度和纬度 127.0.0.1:6379> geopos china:city wuhan 1) 1) "114.29857403039932251" 2) "30.58435486605102227" 127.0.0.1:6379> geopos china:city nanjing aomen 1) 1) "118.76741319894790649" 2) "32.04154071334338738" 2) 1) "113.54913264513015747" 2) "22.19874952821576386"
3、GEODIST 返回两个指定位置之间的距离
使用场景:
# 查看距离朋友有多远,即两人之间的距离
语法:
# 返回两个给定位置之间的距离 GEODIST key member1 member2 [unit]
规则:
# 如果两个位置之间的其中一个不存在, 那么命令返回空值。 # 指定单位的参数 unit 必须是以下单位的其中一个: - m 表示单位为米。 - km 表示单位为千米。 - mi 表示单位为英里。 - ft 表示单位为英尺。 # 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。
案例:
# 北京距离南京的直线距离 127.0.0.1:6379> geodist china:city beijing nanjing "899992.6369" # 武汉距离重庆的直线距离,单位是km千米 127.0.0.1:6379> geodist china:city wuhan chongqing km "759.1648"
4、georadius 以给定的经纬度为中心, 找出某一半径内的元素
使用场景:
# 附近的人 (第一步打开定位,第二步获得所有附近的人的地址,第三步通过半径来查询) # 附近的50人(另指定人的数量)
语法:
# 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。 GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
规则:
# 范围可以使用以下其中一个单位: - m 表示单位为米。 - km 表示单位为千米。 - mi 表示单位为英里。 - ft 表示单位为英尺。 # 在给定以下可选项时, 命令会返回额外的信息: - WITHDIST:在返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。 - WITHCOORD:将位置元素的经度和维度也一并返回。 - WITHHASH:以52位有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中的作用并不大。 # 使用 COUNT <count> 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。 # 命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式: - ASC:根据中心的位置,按照从近到远的方式返回位置元素。 - DESC:根据中心的位置,按照从远到近的方式返回位置元素。
案例:
# 以 110 , 30 这个经纬度为中心,寻找方圆1000km内的城市 127.0.0.1:6379> georadius china:city 110 30 1000 km 1) "chongqing" 2) "aomen" 3) "xianggang" 4) "wuhan" 5) "nanjing" # 以 110 , 30 这个经纬度为中心,寻找方圆500km内的城市 127.0.0.1:6379> georadius china:city 110 30 500 km 1) "chongqing" 2) "wuhan" # 显示距离中心500km内的城市的位置信息(经纬度) 127.0.0.1:6379> georadius china:city 110 30 500 km withcoord 1) 1) "chongqing" 2) 1) "106.50495976209640503" 2) "29.53315530684997015" 2) 1) "wuhan" 2) 1) "114.29857403039932251" 2) "30.58435486605102227" # 显示距离中心500km内的城市的直线距离 127.0.0.1:6379> georadius china:city 110 30 500 km withdist 1) 1) "chongqing" 2) "341.4052" 2) 1) "wuhan" 2) "417.8920" # 显示距离中心500km内的城市的位置信息、直线距离、第一项 127.0.0.1:6379> georadius china:city 110 30 500 km withcoord withdist count 1 1) 1) "chongqing" 2) "341.4052" 3) 1) "106.50495976209640503" 2) "29.53315530684997015" # 显示距离中心500km内的城市,由远到近 127.0.0.1:6379> georadius china:city 110 30 1000 km desc 1) "xianggang" 2) "aomen" 3) "nanjing" 4) "wuhan" 5) "chongqing"
5、GEORADIUSBYMEMBER 根据位置元素找出位于指定范围内的元素
使用场景:
# 城市与城市之间的距离、导航距离等
语法:
# 这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点指定成员的位置被用作查询的中心。 GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
案例:
# 根据位置元素,查询指定范围内的元素 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km 1) "nanjing" 2) "beijing" 127.0.0.1:6379> GEORADIUSBYMEMBER china:city wuhan 500 km 1) "wuhan" 2) "nanjing"
6、GEOHASH 返回一个或多个位置元素的 Geohash 表示
语法:
# 返回一个或多个位置元素的Geohash表示,该命令将返回11个字符的Geohash字符串 GEOHASH key member [member ...]
案例:
# 将位置元素的经纬度转换成11位的hash值显示 # 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近 127.0.0.1:6379> GEOHASH china:city beijing nanjing 1) "wx4g0b7xre0" 2) "wtsqq8gz920"
7、GEO 底层的实现原理其实就是 Zset
可以使用Zset命令来操作Geospatial地理位置
# 查看地图中全部的元素 127.0.0.1:6379> zrange china:city 0 -1 1) "chongqing" 2) "aomen" 3) "xianggang" 4) "xiamen" 5) "wuhan" 6) "nanjing" 7) "beijing" # 移除指定元素 127.0.0.1:6379> zrem china:city aomen (integer) 1 127.0.0.1:6379> zrange china:city 0 -1 1) "chongqing" 2) "xianggang" 3) "xiamen" 4) "wuhan" 5) "nanjing" 6) "beijing"
7.2 Hyperloglog 基数统计
1、什么是基数?
一个数据集内不重复的元素,且可以接受误差。
2、简介
Redis 2.8.9 版本就更新了 Hyperloglog 数据结构,Redis Hyperloglog 基数统计的算法。
3、使用场景
网页的 UV 即页面访问量(例如,一个人访问一个网站多次,但是还是算作一个人)
传统的方式, set(无序不重复)保存用户的id,然后就可以统计 set 中的元素数量作为标准判断。这个方式如果保存大量的用户id,就会比较麻烦,占内存, 我们的目的是为了计数,而不是保存用户id。
现在的方式,可以使用 Hyperloglog进行存储,占用的内存是固定,2^64 不同元素的基数,只需要12KB内存。如果要从内存角度来比较的话Hyperloglog首选。可能会出现0.81%的 错误率,统计UV任务时,是可以忽略不计的。
4、案例
PFADD 创建元素 PFCOUNT 基数统计(不统计重复数据) PFMERGE 合并元素
# 创建第一组元素 my1 127.0.0.1:6379> PFADD my1 a b c d e f g h i j k (integer) 1 # 统计 my1 元素的基数数量 127.0.0.1:6379> PFCOUNT my1 (integer) 11 # 创建第二组元素 my2 127.0.0.1:6379> PFADD my2 j k l m n a d e o p (integer) 1 # 统计 my2 元素的基数数量 127.0.0.1:6379> PFCOUNT my2 (integer) 10 # 合并两组 my1 my2 => my3 并集 127.0.0.1:6379> PFMERGE my3 my1 my2 OK # 统计 my3 元素的基数数量,即并集的数量 127.0.0.1:6379> PFCOUNT my3 (integer) 16
5、测试使用
如果允许容错,那么一定可以使用 Hyperloglog。
如果不允许容错,就使用 set 或者自己的数据类型即可。
7.3 Bitmap 位存储
1、使用场景
统计用户信息,活跃 或 不活跃、 登录 或 未登录、 打卡 或 未打卡。涉及 两个状态的,都可以使用Bitmap位存储。
Bitmap 位图也是一种数据结构,都是操作二进制位来进行记录,就只有 0 和 1 两个状态。
等价于 365 天 = 365 bit 1字节 = 8bit 46 个字节左右,即若记录某个学生的一年打卡情况,则只需耗费46个字节左右。
2、案例
# 使用Bitmap来记录周一到周日的打卡,例如,周一: 1 周二: 1 周三: 1 周四:0 ...... 127.0.0.1:6379> setbit ding 0 1 (integer) 0 127.0.0.1:6379> setbit ding 1 1 (integer) 0 127.0.0.1:6379> setbit ding 2 1 (integer) 0 127.0.0.1:6379> setbit ding 3 0 (integer) 0 127.0.0.1:6379> setbit ding 4 1 (integer) 0 127.0.0.1:6379> setbit ding 5 1 (integer) 0 127.0.0.1:6379> setbit ding 6 0 (integer) 0 127.0.0.1:6379> setbit ding 7 0 (integer) 0 # 查看某一天是否有打卡,返回1则打卡,返回0则未打卡 127.0.0.1:6379> getbit ding 1 (integer) 1 127.0.0.1:6379> getbit ding 3 (integer) 0 # 统计操作,统计打卡的天数,即统计这周的打卡记录,就可以看到是否有全勤 127.0.0.1:6379> bitcount ding (integer) 5