Redis五大基本数据类型

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Redis-Key

一些基本命令:

keys * # 查看所有的键
EXISTS xxx # 判断有没有该键 返回1则有,0则无
move name 1 # 将当前库的name键 移动到1号数据库中
EXPIRE name 10 # 10秒后name过期
ttl name # 查看当前key的剩余时间
type name # 查看当前类型


127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name 
"gump"
127.0.0.1:6379> EXPIRE name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name 
(nil)
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> EXISTS key1 
(integer) 1
# 往某个key中追加字符串,如果没有这个key则会相当于新增一个key
127.0.0.1:6379> APPEND key1 "hello" 
(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 ",Gump"
(integer) 12
127.0.0.1:6379> STRLEN key1
(integer) 12
127.0.0.1:6379> get key1
"v1hello,Gump"

###############################################
# i++
# 步长
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 
(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 # 自增10,可以设置步长,指定增量
(integer) 11
127.0.0.1:6379> get views
"11"
127.0.0.1:6379> DECRBY views 5 # 自减5
(integer) 6
127.0.0.1:6379> get views
"6"

###############################################
# 字符串范围 range
127.0.0.1:6379> get key1
"v1hello,Gump"
127.0.0.1:6379> GETRANGE key1 0 3 # 截取字符串 [0,3]
"v1he"
127.0.0.1:6379> GETRANGE key1 0 -1 # 获得全部的字符串 和 get key 是一样的
"v1hello,Gump"

# 替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> SETRANGE key2 1 xx # 替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"

###############################################
# setex (set with expire) 设置过期时间
# setnx (set if not exists) 不存在再设置 (在分布式锁中会常常使用)
127.0.0.1:6379> setex key3 30 "hello" # 设置key3的值为hello,过期时间为30秒
OK
127.0.0.1:6379> ttl key3
(integer) 24
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx mykey "redis" # 如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> setnx mykey "MongoDB" # 如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"

###############################################
# mset 
# mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> get k3 
"v3"
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 # msetnx 是一个原子性的操作,要么都成功,要么都失败
(integer) 0
127.0.0.1:6379> get k4
(nil)

# 对象
set user:1 {name:zhangsan,age:3} # 设置一个user:1 对象,值为json字符串来保存对象

# 这里的key是一个巧妙的设计:user:{id}:{field},如此设计在redis中是完全ok的

127.0.0.1:6379> mset user:1:name zhangsan user:1:age 3
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "3"

###############################################
# 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"

​ String类似的使用场景:value除了是我们的字符串还可以是我们的数字!

​ 1、计数器

​ 2、统计多单位的数量 uid:391605991:follow 0

​ 3、粉丝数

​ 4、对象缓存存储

二、List类型(列表)

基本数据类型,列表

在redis里面,我们可以把list玩成栈、队列、阻塞队列!

###############################################
# 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 four # 将一个值或者多个值,插入到列表的尾部(右)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"

###############################################
# LPOP
# RPOP
127.0.0.1:6379> LRANGE list 0 -1 
1) "three"
2) "two"
3) "one"
4) "four"
127.0.0.1:6379> LPOP list # 移除列表中的第一个元素
"three"
127.0.0.1:6379> RPOP list # 移除列表中的最后一个元素
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"

###############################################
# LINDEX 通过下标获取list中的某一个值
127.0.0.1:6379> lindex list 0 
"two"
127.0.0.1:6379> lindex list 1
"one"

###############################################
# LLEN 返回列表的长度
127.0.0.1:6379> LLEN list 
(integer) 2

###############################################
# 移除指定的值
127.0.0.1:6379> LRANGE list 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> RPUSH list three
(integer) 4
127.0.0.1:6379> LREM list 1 one # 移除list集合中指定个数的value,精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "three"
3) "three"
127.0.0.1:6379> LREM list 0 three # 为0 则移除全部是three的值
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "two"

###############################################
# Ltrim 修剪: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
127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取mylist的长度,这个list已经被改变了,截断了只剩下截取的元素
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 mylist2 # 移除mylist列表的最后一个元素,并将它移动到mylist2列表中
"hello2"
127.0.0.1:6379> LRANGE mylist 0 -1 # 查看原来的列表
1) "hello"
2) "hello1"
127.0.0.1:6379> LRANGE mylist2 0 -1
1) "hello2"

###############################################
# 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 value2 value3
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "value3"
2) "value2"
3) "value1"
127.0.0.1:6379> lset list 0 item # 如果存在,则更新下标的值
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "item"
2) "value2"
3) "value1"
127.0.0.1:6379> lset list 3 item3 # 如果下标不存在,则会报错!
(error) ERR index out of range

###############################################
Linsert # 将某个具体的value插入到列表中某个元素的前面或者后面
127.0.0.1:6379> RPUSH mylist hello world
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" "other" # 在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" "Like" # 在world之后插入Like元素
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "Like"

小结:

​ 1、它实际上是一个链表,before Node after,left、right都可以插入值。

​ 2、如果key不存在,创建新的链表

​ 3、如果key存在,新增内容

​ 4、如果移除了所有的值,空链表,也代表不存在

​ 5、在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点

三、Set类型(集合)

set中的值是不能重复的

###############################################
127.0.0.1:6379> sadd myset "hello" # set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd myset "gump"
(integer) 1
127.0.0.1:6379> sadd myset "love"
(integer) 1
127.0.0.1:6379> SMEMBERS myset # 查看指定set的所有值
1) "gump"
2) "hello"
3) "love"
127.0.0.1:6379> SISMEMBER myset hello # 判断某一个值是不是在set集合中
(integer) 1

###############################################
127.0.0.1:6379> SCARD myset # 获取set集合中的个数
(integer) 3
127.0.0.1:6379> sadd myset "love" # 不能添加重复的
(integer) 0
127.0.0.1:6379> sadd myset "love2"
(integer) 1
127.0.0.1:6379> 
127.0.0.1:6379> SCARD myset
(integer) 4

###############################################
# Srem
127.0.0.1:6379> SREM myset love2 # 移除指定set集合中的元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "gump"
2) "hello"
3) "love"

###############################################
# set 无序不重复集合,抽随机
127.0.0.1:6379> SMEMBERS myset
1) "gump"
2) "hello"
3) "love"
127.0.0.1:6379> SRANDMEMBER myset # 随机抽出一个元素
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"love"
127.0.0.1:6379> SRANDMEMBER myset 2 # 随机抽出指定个数的元素
1) "gump"
2) "love"

###############################################
# 随机删除key
127.0.0.1:6379> SMEMBERS myset
1) "gump"
2) "hello"
3) "love"
127.0.0.1:6379> SPOP myset # 随机移除元素,可指定移除几个
"hello"
127.0.0.1:6379> SMEMBERS myset
1) "gump"
2) "love"

###############################################
# 将一个指定的值,移动到另外一个set集合中
127.0.0.1:6379> sadd myset1 one
(integer) 1
127.0.0.1:6379> sadd myset1 two
(integer) 1
127.0.0.1:6379> sadd myset1 three
(integer) 1
127.0.0.1:6379> sadd myset2 four
(integer) 1
127.0.0.1:6379> sadd myset2 five
(integer) 1
127.0.0.1:6379> sadd myset2 six
(integer) 1
127.0.0.1:6379> SMOVE myset1 myset2 one # 将一个指定的值,移动到另外一个set集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "six"
2) "one"
3) "four"
4) "five"

###############################################
# 在微博和b站中经常可以看到共同关注,(交集)
# 数字集合类:
# - 交集 SINTER
# - 并集 SUNION
# - 差集 SDIFF
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 # 查出属于key1且不属于key2的元素
1) "b"
2) "a"
127.0.0.1:6379> SINTER key1 key2 # 查出属于key1且属于key2的元素 共同关注就此实现
1) "c"
127.0.0.1:6379> SUNION key1 key2 # 查出属于key1和属于key2的元素
1) "b"
2) "c"
3) "e"
4) "a"
5) "d"

​ 微博、b站将用户所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!

共同关注、共同爱好、二度好友,推荐好友(六度分割理论↓↓↓)

六度分割理论:并不是说任何人与人之间的联系都必须要通过六个层次才会产生联系,而是表达了这样一个重要的概念:任何两位素不相识的人之间,通过一定的联系方式,总能够产生必然联系或关系。

四、Hash类型(哈希)

Map集合,key-Map集合!这时候这个值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-value!

127.0.0.1:6379> HSET myhash name gump  # set一个具体的 key-value
(integer) 1
127.0.0.1:6379> HSET myhash age 21
(integer) 1
127.0.0.1:6379> HGET myhash name # 获取一个字段值
"gump"
127.0.0.1:6379> HMSET myhash name gump2 age 18 # set多个 key-value
OK
127.0.0.1:6379> HMGET myhash name age # 获取多个 key-value
1) "gump2"
2) "18"
127.0.0.1:6379> HGETALL myhash # 获取全部的数据
1) "name"
2) "gump2"
3) "age"
4) "18"
127.0.0.1:6379> HDEL myhash age # 删除hash指定的字段,对应的value值也消失了
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "name"
2) "gump2"

###############################################
Hlen
127.0.0.1:6379> HLEN myhash # 获取hash表的字段数量
(integer) 1
127.0.0.1:6379> HMSET myhash age 1 name2 wiice age2 14
OK
127.0.0.1:6379> HGETALL myhash
1) "name"
2) "gump2"
3) "age"
4) "1"
5) "name2"
6) "wiice"
7) "age2"
8) "14"
127.0.0.1:6379> HLEN myhash
(integer) 4

###############################################
127.0.0.1:6379> HEXISTS myhash name # 判断hash中的指定字段是否存在
(integer) 1

###############################################
# 只获得所有的字段
# 只获取所有的值
127.0.0.1:6379> HKEYS myhash # 只获得所有的字段
1) "name"
2) "age"
3) "name2"
4) "age2"
127.0.0.1:6379> HVALS myhash # 只获取所有的值
1) "gump2"
2) "1"
3) "wiice"
4) "14"

###############################################
127.0.0.1:6379> hset myhash num 1 
(integer) 1
127.0.0.1:6379> HINCRBY myhash num 2 # 指定增量为2
(integer) 3
127.0.0.1:6379> HINCRBY myhash num -1 # -1则减1
(integer) 2
127.0.0.1:6379> HSETNX myhash name3 doit # 如果不存在则可以设置
(integer) 1
127.0.0.1:6379> HSETNX myhash name3 doit2 # 如果存在则不可以设置
(integer) 0

​ hash变更的数据 user name age ,尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,而String更适合字符串的存储。

五、Zset类型(有序集合)

在set的基础上,增加了一个值,set k1 v1 zset k1 score1 v1

127.0.0.1:6379> zadd myset 1 one # 添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three # 添加多个值
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1 # 获取所有的值
1) "one"
2) "two"
3) "three"
###############################################
# 排序如何实现
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 5000 zhangsan 500 kuangshen # 添加三个用户 
(integer) 2
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf  # 显示全部的用户,从小到大排序
1) "kuangshen"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 显示具体的值
1) "kuangshen"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores # 从负无穷到2500的范围
1) "kuangshen"
2) "500"
3) "xiaohong"
4) "2500"
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores # 从大到小排序
1) "zhangsan"
2) "5000"
3) "xiaohong"
4) "2500"
5) "kuangshen"
6) "500"
127.0.0.1:6379> ZRANGE salary 0 -1 withscores
1) "kuangshen"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"

###############################################
127.0.0.1:6379> ZREM salary zhangsan # 移除某个元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1 withscores
1) "kuangshen"
2) "500"
3) "xiaohong"
4) "2500"
127.0.0.1:6379> ZCARD salary # 获取集合中的个数
(integer) 2

###############################################
127.0.0.1:6379> ZADD myset 1 hello 2 world 3 gump
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 3 # 获取指定区间的成员数量
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 2
(integer) 2

Q.E.D.