1.Redis主要数据类型分类

Redis中存储数据常用的数据类型主要有五种:String、List、Set、Sorted Set、Hash,这五种数据结构在Redis中存储数据的命令掌握对于我们后期在使用Java框架封装类操作Redis的API了解是非常重要的。所以在这里对这五种数据结构进行一一汇总,另外也简单介绍一下bitmaps、hyperloglogs、geospatial这三种类型。

【数据库】Redis(2)--Redis的常用数据类型及命令-LMLPHP

1.1.String类型

String类型在Redis中常用的操作:

①get/set/exists/append/strlen命令:

127.0.0.1:6379> set key1 v1  # 设置值
OK
127.0.0.1:6379> get key1    # 获取值
"v1"
127.0.0.1:6379> keys *    # 获取所有的值
1) "key1"
127.0.0.1:6379> EXISTS key1    # 判断key1是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello"    # 向key1中追加"hello",如果Key1不存在,那就相当于set key1
(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 ", fengye"
(integer) 15
127.0.0.1:6379> STRLEN key1
(integer) 15
127.0.0.1:6379> get key1
"v1hello, fengye"

②自增/减、步长(浏览量、点击数):

# +1/-1与+n/-n
127.0
.0.1:6379> set views 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> decr views (integer) 0 127.0.0.1:6379> decr views (integer) -1 127.0.0.1:6379> get views "-1" 127.0.0.1:6379> INCRBY views 10 # 增加 n (integer) 9 127.0.0.1:6379> INCRBY views 10 (integer) 19 127.0.0.1:6379> DECRBY views 5 # 减少 n (integer) 14

③字符串截取:

127.0.0.1:6379> set key1 "hello, fengye"
OK
127.0.0.1:6379> get key1
"hello, fengye"
127.0.0.1:6379> GETRANGE key1 0 4    # 截取闭区间 [0, 4]的字符串
"hello"
127.0.0.1:6379> GETRANGE key1 0 -1   # 截取全部的字符串,和get key1同理
"hello, fengye"

④替换:

127.0.0.1:6379> set key2 abcddefg
OK
127.0.0.1:6379> get key2
"abcddefg"
127.0.0.1:6379> SETRANGE key2 2 XXX   #  替换指定位置开始的字符串
(integer) 8
127.0.0.1:6379> get key2
"abXXXefg"

⑤setex(set with expire)与setnx(set if not exist):

#setex :设置过期时间
#setnx :不存在当前key才会设置值,在分布式锁中常常使用
127.0
.0.1:6379> setex key3 30 "hello" # 设置过期时间为30s,30s后过期 OK 127.0.0.1:6379> ttl key3 (integer) 21 127.0.0.1:6379> get key3 "hello" 127.0.0.1:6379> setnx mykey "redis" #设置mykey的值为redis,当mykey不存在时设置成功 (integer) 1 127.0.0.1:6379> keys * 1) "key1" 2) "key2" 3) "mykey" 127.0.0.1:6379> ttl key3 (integer) -2 127.0.0.1:6379> setnx mykey "mongoDb" #当mykey已经存在了,设置mykey会失败 (integer) 0 127.0.0.1:6379> get mykey "redis"

⑥同时设置多个值mset/mget/msetnx:

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3    #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3    #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 y1 k4 v4   #同时获取多个值,msetnx是一个原子性操作,要么一起成功,要么一起失败
(integer) 0

127.0.0.1:6379> get k4
(nil)

⑦设置对象的值:

127.0.0.1:6379> set user:2 {name:lisi,age:3}   # 使用json字符串来保存user的值
OK
127.0.0.1:6379> get user:2
"{name:lisi,age:3}"
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2   # 使用user:1:name与user1:1:age来保存值,user:{id}:{field}作为key来保存值
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

⑧getset(先获取后设置):

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"

1.2.List类型

①lpush/rpush/lrange(压栈):

127.0.0.1:6379> LPUSH list one   # 将一个或多个值放到列表的头部(左push)
(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
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    # 将一个或多个值放到列表的尾部(右push)
(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> LPOP list  # 左移除列表中的一个元素
"three"
127.0.0.1:6379> RPOP list  # 右移除列表中的一个元素
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"

③lindex(list index的简写):

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

④llen:

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> Llen list  # 返回列表的长度
(integer) 3

⑤Lrem:

127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 one   # 移除list集合中指定个数的元素,精确匹配个数并移除
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "two"

⑥Lrem:

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   # 通过下标截取指定的长度,截取之后List会被改变,只剩下截取后的元素
OK
127.0.0.1:6379> LRANGE list 0 -1
(empty list or set)
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 myotherlist  #右弹栈,移除列表中最后一个元素并放入新的列表元素中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello1"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "hello2"

⑧lset:

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 other   #如果更新范围超出限制,也会抛出异常
(error) ERR index out of range

⑨Linsert:

Linsert将某一个具体的value插入到列表中的某个元素的前面或者后面

127.0.0.1:6379> Rpush mylist "hello"
(integer) 1
127.0.0.1:6379> Rpush mylist "world"
(integer) 2
127.0.0.1:6379> LINSERT mylist before "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" "new"
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"

1.3.Set类型

redis中Set集合中的元素是不能重复的。

①sadd/smembers/sismember/scard

127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "fengye"
(integer) 1
127.0.0.1:6379> sadd myset "love fengye"
(integer) 1
127.0.0.1:6379> SMEMBERS myset  #查看myset中所有的值
1) "fengye"
2) "love fengye"
3) "hello"127.0.0.1:6379> SISMEMBER myset hello  #判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0

  127.0.0.1:6379> scard myset  #获取set集合中内容元素的个数
  (integer) 4

②srem

127.0.0.1:6379> SMEMBERS myset
1) "fengye"
2) "lovekuangshen2"
3) "love fengye"
4) "hello"
127.0.0.1:6379> srem myset lovekuangshen2   #移除某一个元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "fengye"
2) "love fengye"
3) "hello"

③srandmember

127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"love fengye"
127.0.0.1:6379> SRANDMEMBER myset
"fengye"
127.0.0.1:6379> SRANDMEMBER myset 2  #随机抽选出指定个数的元素
1) "hello"
2) "love fengye"

④spop

127.0.0.1:6379> spop myset  #随机删除集合中的一些元素
"fengye"
127.0.0.1:6379> spop myset
"love fengye"
127.0.0.1:6379> SMEMBERS myset
1) "hello"

⑤smove

127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "world"
(integer) 1
127.0.0.1:6379> sadd myset "fengye"
(integer) 1
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> smove myset myset2 "fengye"  #将指定的元素从一个set移动到另一个set集合中
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SMEMBERS myset2
1) "fengye"
2) "set2"

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

1.4.Hash

①hset/hget/hmget/hgetall:

127.0.0.1:6379> hset myhash field1 fengye  # hset一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash field1
"fengye"
127.0.0.1:6379> hmset myhash field1 hello field2 world    #set多个key value
OK
127.0.0.1:6379> hmget myhash field1 field2    #获取多个字段值
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash  #获取全部的数据
1) "field1"
2) "hello"
3) "field2"
4) "world"

#使用hash存取对象数据

127.0.0.1:6379> hmset myhash username zhangsan sex '男' age 24
OK
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
5) "field3"
6) "5"
7) "filed3"
8) "1"
9) "field4"
10) "hello"
11) "username"
12) "zhangsan"
13) "sex"
14) "\xe7\x94\xb7"
15) "age"
16) "24"

②hdel:

127.0.0.1:6379> hdel myhash field1  #删除hash中指定的key字段,对应的value值也就没有了
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"

③hlen:

127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hlen myhash  # 获取hash表的字段数量
(integer) 2

④hexists:

127.0.0.1:6379> HEXISTS myhash field1  #判断hash中的key是否存在
(integer) 1
127.0.0.1:6379> HEXISTS myhash field3
(integer) 0

⑤Hkeys/Hvals:

127.0.0.1:6379> HKEYS myhash   # 查询所有的keys
1) "field2"
2) "field1"
127.0.0.1:6379> HVALS myhash   # 查询所有的vals
1) "world"
2) "hello"

⑥hincrby/hsetnx:

127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1  #hash指定增量
(integer) 6
127.0.0.1:6379> HINCRBY myhash field3 -1  #hash自减
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hello   #不存在则设置值
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 world  #存在则无法设置,分布式锁
(integer) 0

1.5.Sorted Set有序集合类

①zadd/zrange:

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"

②zrangebyscore:

127.0.0.1:6379> clear
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 4000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 1000 fengye
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf  #按照薪资高低升序排序
1) "fengye"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores  #按照薪资高低升序排序,附带薪资

1) "fengye"
2) "1000"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "4000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores 

1) "fengye"
2) "1000"
3) "xiaohong"
4) "2500"

③zrem:

127.0.0.1:6379> ZREM salary zhangsan  #移除sorted set中指定的元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "fengye"

④zcard:

127.0.0.1:6379> ZCARD salary  #获取有序集合中元素的个数
(integer) 2

⑤zrevrage:

127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores  #从大到小排列
1) "xiaohong" 
2) "2500"
3) "fengye"
4) "1000"

⑥zcount:

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

2.Redis几种特殊类型分类

2.1.Geospatial地理位置

Redis通过Geospatial可以根据地理位置如经度、纬度查询出两地之间的距离。主要分为以下几个命令:

①geoadd:

# 添加规则:除两极不能添加外,其它均能添加
# 参数 key 经度 纬度 名称
# 有效的经度从-180度到180度
# 有效的纬度从-85.05112878度到85.05112878度
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(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.50 29.53 chongqi 114.05 22.52 shengzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2

②geopos:

127.0.0.1:6379> geopos china:city beijing   # 获取指定的成员的经度和纬度
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city beijing xian
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "108.96000176668167114"
   2) "34.25999964418929977"

③geodist:

计算两个城市地区之间的直线距离:

  • m表示单位米
  • km表示单位千米
  • mi表示单位英里
  • ft表示单位英尺
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km  # 查找北京到上海的直线距离,单位km
"1067.3788"
127.0.0.1:6379> geodist china:city beijing hangzhou km
"1127.3378"

④georadius:

以给定的经纬度为中心,找出某一半径内的元素:

127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 1000 km   #获取当前经度纬度下1000km以内的城市
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km
1) "chongqi"
2) "xian"
127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withdist  #获取该经度纬度下500km以内的城市并附带距离
1) 1) "chongqi"
   2) "383.1094"
2) 1) "xian"
   2) "449.8190"
127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withcoord  #获取该经度纬度下500km以内的城市病显示城市的经度、纬度
1) 1) "chongqi"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"
127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withdist withcoord count 2  #count 2表示只显示2个
1) 1) "chongqi"
   2) "383.1094"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "449.8190"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

⑤georadiusbymember:

127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km  #以城市为中心查询出距离400km的城市
1) "hangzhou"
2) "shanghai"

⑥geohash:

该命令将返回11个字符的geohash字符串

127.0.0.1:6379> geohash china:city beijing chongqi
1) "wx4fbxxfke0"
2) "wm5xzrybty0"

⑦zset命令删除:

geo底层就是zset,所以我们可以使用zset进行删除:

127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> ZREM china:city beijing
(integer) 1

2.2.hyperloglogs

Redis基于hyperloglogs提供了一种更高效的算法来计算两个集合中的元素个数,重复个数不累计。

这种高效率的算法替代了传统使用set集合进行不重复元素的存取计算方式。

hyperloglogs的优点:

  • 占用内存小,存取2^64的不同元素的基数,只需要12kb的内存存储空间
127.0.0.1:6379> PFADD mykey a b c d e f g h i j
(integer) 1
127.0.0.1:6379> PFCOUNT mykey
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j z x c a b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2  #合并两个集合的元素
OK
127.0.0.1:6379> PFCOUNT mykey3  #计算元素的个数,不重复
(integer) 14

注意:使用hyperloglogs有0.81%的错误率,如果不允许容错,需要精确计算的,则不能使用hyoerloglogs。

2.3.Bitmaps类型

Bitmaps使用位0 1进行数据的存储。

适用场景:统计用户信息,活跃与非活跃、登录、打卡

使用Bitmaps来记录一周7天的打卡时间:

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 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
127.0.0.1:6379> getbit sign 3  #查看某一天是否有打卡
(integer) 1
127.0.0.1:6379> getbit sign 6
(integer) 0

  127.0.0.1:6379> BITCOUNT sign  #统计打卡的天数
  (integer) 3

03-28 04:18