Redis是一个KV存储系统,使用C语言编写的我们的key是字符串类型,是唯一的,value的数据类型如下,下面我们就来说一说关于redis一般用哪些数据类型?我们一起去了解并探讨一下这个问题吧!
redis一般用哪些数据类型
Redis是一个KV存储系统,使用C语言编写的。我们的key是字符串类型,是唯一的,value的数据类型如下
5种常用的
string字符串类型list列表类型set集合类型sortedset(zset)有序集合类型hash类型2种不常用的
bitmap位图类型geo地理位置类型1种redis5.0新增的
stream类型既然key是字符串类型,那么key有没有一些约定俗成的一些规则,或者说一些建议的规则呢?
redis key如何设计?
一般使用冒号分隔一般会把表名或者表名的缩写作为key的前缀比如:认证系统的用户表的id为001的key, auth:user:001命名要具有一定的识别性,一看就知道是什么意思key要尽量短一点,短key的效率比长key好一些,后面会讲到1、String字符串Redis的string能存储3种值的类型:字符串,整数,浮点数
1.1、应用场景key和value都是字符串类型的应用场景极为广泛
普通的赋值操作所有的kv存储都可以转换为value为字符串的存储,通过序列化转string,或者普通类型转string. 所以这种场景是最多的。incr可以加上watch监听,实现乐观锁incr实现的是数字递增
setnx可以实现分布式锁value不存在时,可以用于分布式锁,最终可以一个会设置成功,设置成功的就是抢到锁资源的1.2、String字符串类型命令命令行罗列
命令 | 帮助 | 描述 |
set | set key value | 赋值 |
get | get key | 取值 |
getset | getset key value | 取值赋值 |
setnx | setnx key value | 当key不存在时才赋值成功,存在时赋值失败 set key value NX PX 3000 原子操作,可用于分布式锁,px 设置毫秒数 |
append | append key value | 向尾部追加值 |
strlen | strlen key | 获取字符串长度 |
incr | incr key | 递增数字 |
incrby | incrby key increment | 增加指定的整数 |
decr | decr key | 递减数字 |
decrby | decrby key decrement | 减少指定的整数 |
命令行实际操作
127.0.0.1:6379> set name zhangsanOK127.0.0.1:6379> get name"zhangsan"127.0.0.1:6379> getset age 20(nil)127.0.0.1:6379> get age"20"127.0.0.1:6379> setnx lock_01 1001(integer) 1127.0.0.1:6379> setnx lock_01 1001(integer) 0127.0.0.1:6379> setnx lock_01 1002(integer) 0127.0.0.1:6379> append name 1(integer) 9127.0.0.1:6379> get name"zhangsan1"127.0.0.1:6379> strlen name(integer) 9127.0.0.1:6379> incr myid(integer) 1127.0.0.1:6379> incrby myid 2(integer) 3127.0.0.1:6379> decr myid(integer) 2127.0.0.1:6379> decrby myid 2(integer) 0# 设置分布式锁后的值,有效期20s127.0.0.1:6379> set lock_02 1002 NX PX 30000 OK# 30s内重新设置值失败127.0.0.1:6379> set lock_02 1002 NX(nil)# 30s内获取值成功127.0.0.1:6379> get lock_02"1002"# 30s后获取值为空127.0.0.1:6379> get lock_02(nil)# 重新设置值成功127.0.0.1:6379> set lock_02 1003 NX PX 30000OK127.0.0.1:6379> get lock_02"1003"127.0.0.1:6379>
list列表可以存储有序并且可以重复的元素。
获取头部或尾部的数据极快列表最多存储2^32 -1个元素,大概40亿看下面的命令,我们就知道这是一个双向列表。左进右出可以作为队列,左进左出可以作为栈使用。其实就是先进先出队列,后进先出为栈。
可以存储各种各样的列表数据。比如用户列表
2.2、list列表命令命令罗列
命令 | 帮助 | 描述 |
lpush | lpush key v1 v2 n3 ... vn | 从左侧插入列表 |
lpop | lpop key | 从列表左侧取出 |
rpush | rpush key v1 v2 n3 ... vn | 从右侧插入列表 |
rpop | rpop key | 从列表右侧取出 |
lpushx | lpushx key value | 将值插入到列表头部 |
rpushx | rpushx key value | 将值插入到列表尾部 |
blpop | blpop key timeout | 从列表左侧取出,如果为空阻塞,timeout最大阻塞时间(s) |
brpop | brpop key timeout | 从列表右侧取出,如果为空阻塞,timeout最大阻塞时间(s) |
llen | llen key | 获得列表中元素个数 |
lindex | lindex key index | 获得列表中下标为index的元素 index从0开始 |
lrange | lrange key start end | 返回列表中指定区间的元素,区间通过start和end指定 |
lrem | lrem key count value | 删除列表中与value相等的元素 当count>0时, lrem会从列表左边开始删除;当count<0时, lrem会从列表后边开始删除;当count=0时, lrem删除所有值为value的元素 |
lset | lset key index value | 将列表index位置的元素设置成value的值 |
ltrim | ltrim key start end | 对列表进行修剪,只保留start到end区间 |
rpoplpush | rpoplpush key1 key2 | 从key1列表右侧弹出并插入到key2列表左侧 |
brpoplpush | brpoplpush key1 key2 | 从key1列表右侧弹出并插入到key2列表左侧,会阻塞 |
linsert | linsert key BEFORE/AFTER pivot value | 将value插入到列表,且位于值pivot之前或之后 |
命令执行
127.0.0.1:6379> lpush name2 zhangsan lisi wangwu(integer) 3127.0.0.1:6379> lpop name2"wangwu"127.0.0.1:6379> rpush name3 zhangsan lisi wangwu(integer) 3127.0.0.1:6379> rpop name3"wangwu"127.0.0.1:6379> lpushx name2 niuqi(integer) 3127.0.0.1:6379> lrange name2 0 51) "niuqi"2) "lisi"3) "zhangsan"127.0.0.1:6379> rpushx name3 niuqi(integer) 3127.0.0.1:6379> lrange name3 0 51) "zhangsan"2) "lisi"3) "niuqi"127.0.0.1:6379> blpop name2 11) "name2"2) "niuqi"127.0.0.1:6379> brpop name3 11) "name3"2) "niuqi"127.0.0.1:6379> llen name2(integer) 2127.0.0.1:6379> lindex name2 0"lisi"127.0.0.1:6379> lindex name2 1"zhangsan"
Set集合,就是表示value唯一,并且无需的集合。
存储各种不需要顺序的数据集合。比如用户随机随机抽奖
3.2、Set集合命令命令罗列
命令 | 帮助 | 描述 |
sadd | sadd key v1 v2 n3 ... vn | 为集合添加新成员 |
srem | srem key mem1 mem2 ...memn | 删除集合中指定成员 |
smembers | rsmembers key | 从获得集合中所有元素 |
spop | spop key | 返回集合中一个随机元素,并将该元素删除 |
srandmember | srandmember key | 将返回集合中一个随机元素,不会删除该元素 |
scard | scard key | 获得集合中元素的数量 |
sismember | sismember key member | 判断元素是否在集合内 |
sinter | sinter key1 key2 key3 | 求多集合的交集 |
sdiff | sdiffff key1 key2 key3 | 求多集合的差集 |
sunion | sunion key1 key2 key3 | 求多集合的并集 |
命令操作
127.0.0.1:6379> sadd name4 zhangsan lisi wangwu(integer) 3127.0.0.1:6379> srem zhangsan(error) ERR wrong number of arguments for 'srem' command127.0.0.1:6379> srem name4 zhangsan(integer) 1127.0.0.1:6379> smembers name4 1) "lisi"2) "wangwu"127.0.0.1:6379> spop name4"lisi"127.0.0.1:6379> srandmember name4"wangwu"127.0.0.1:6379> scard name4(integer) 1127.0.0.1:6379> sismember name4 wangwu(integer) 1127.0.0.1:6379> sismember name4 wangwu(integer) 1# 定义两个集合 求交集,差集,并集127.0.0.1:6379> sadd name5 zhangsan lisi(integer) 2127.0.0.1:6379> sadd name6 lisi wangwu(integer) 2127.0.0.1:6379> sinter name5 name61) "lisi"127.0.0.1:6379> sdiff name5 name61) "zhangsan"127.0.0.1:6379> sunion name5 name61) "lisi"2) "wangwu"3) "zhangsan"
sortedset是一个有序集合,元素本身跟set一样,是不重复的,为每一个元素添加了一个分数(score)根据分数的不同可以进行排序。分数可以重复。
有序列表被广泛使用在各种排行榜业务上:比如销量排行,用户点击率排行等
4.2、sortedset命令命令罗列
命令 | 帮助 | 描述 |
zadd | zadd key score1 v1 score2 v2 score1v3 ... scoren vn | 为有序集合添加新成员 |
zrem | zrem key mem1 mem2 ...memn | 删除有序集合中指定成员 |
zcard | zcard key | 获得有序集合中的元素数量 |
zcount | zcount key min max | 返回集合中score值在[min,max]区间的元素数量 |
zincrby | zincrby key increment member | 在集合的member分值上加increment |
zscore | zscore key member | 获得集合中member的分值 |
zrank | zrank key member | 获得集合中member的排名(按分值从小到大) |
zrevrank | zrevrank key member | 获得集合中member的排名(按分值从大到小) |
zrange | zrange key start end | 获得集合中指定区间成员,按分数递增排序 |
zrevrange | zrevrange key start end | 获得集合中指定区间成员,按分数递减排序 |
命令操作
127.0.0.1:6379> zadd test:001 20 zhangsan 50 lisi 30 wangwu 90 niuqi (integer) 4127.0.0.1:6379> zcount test:001 0 2(integer) 0127.0.0.1:6379> zcount test:001 20 30(integer) 2127.0.0.1:6379> zcard test:001(integer) 4127.0.0.1:6379> zrem test:001 wangwu(integer) 1127.0.0.1:6379> zincrby test:001 10 zhangsan"30"127.0.0.1:6379> zscore test:001 zhangsan"30"127.0.0.1:6379> zrank test:001 zhangsan(integer) 0127.0.0.1:6379> zrank test:001 niuqi(integer) 2127.0.0.1:6379> zrevrank test:001 niuqi(integer) 0127.0.0.1:6379> zrevrank test:001 zhangsan(integer) 2127.0.0.1:6379> zrange test:001 0 51) "zhangsan"2) "lisi"3) "niuqi"127.0.0.1:6379> zrevrange test:001 0 51) "niuqi"2) "lisi"3) "zhangsan"
hash就是要存储一个key对应多个值。比如以key的用户ID,value为用户整个对象的缓存为例,这种数据就很适合使用hash存储。
5.2、hash命令命令罗列
命令 | 帮助 | 描述 |
hset | hset key field value | 赋值,不区别新增或修改 |
hmset | hmset key field1 value1 field2 value2 | 批量赋值 |
hsetnx | hsetnx key field value | 获得有序集合中的元素数量 |
hexists | hexists key filed | 查看某个field是否存在 |
hget | hget key field | 获取一个字段值 |
hmget | hmget key field1 field2 ... | 获取所有 |
hgetall | hgetall key | 获得集合中member的排名(按分值从小到大) |
hdel | hdel key field1 field2 | 删除指定字段 |
hincrby | hincrby key field increment | 指定字段自增increment |
hlen | hlen key | 获得字段数量 |
命令操作
# 其实直接使用hset多个key value也是可以的127.0.0.1:6379> hset user:001 id 001 name zhangsan(integer) 2127.0.0.1:6379> hget user:001 id"001"127.0.0.1:6379> hget user:001 name"zhangsan"127.0.0.1:6379> hmset user:001 age 20 sex 1OK127.0.0.1:6379> hsetnx user:001 age 30(integer) 0127.0.0.1:6379> hexists user:001 age(integer) 1127.0.0.1:6379> hget user:001 age"20"# 使用hget多个就会报错127.0.0.1:6379> hget user:001 age name(error) ERR wrong number of arguments for 'hget' command127.0.0.1:6379> hmget user:001 age name1) "20"2) "zhangsan"127.0.0.1:6379> hgetall user(empty list or set)127.0.0.1:6379> hgetall user:0011) "id"2) "001"3) "name"4) "zhangsan"5) "age"6) "20"7) "sex"8) "1"
bitmap是进行按位操作的,可以极大的节省空间,如果需要小空间存储大量值的时候可以使用它,并且存储的值很简单,就是1bit即可存储。
比如:用户每月签到,客户以用户id为key, 日期作为偏移量,1 表示签到
命令罗列
命令 | 帮助 | 描述 |
setbit | setbit key offffset value | 设置key在offffset处的bit值(只能是0或者1)。 |
getbit | getbit key offffset | 获得key在offffset处的bit值 |
bitcount | bitcount key | 获得key的bit位为1的个数 |
bitpos | bitpos key value | 返回第一个被设置为bit值的索引值 |
bitop | bitop and[or/xor/not] destkey key [key …] | 对多个key 进行逻辑运算后存入destkey中 |
命令操作
# 本月用户签到了四天127.0.0.1:6379> setbit user:sign:001 20220801 1(integer) 0127.0.0.1:6379> setbit user:sign:001 20220803 1(integer) 0127.0.0.1:6379> setbit user:sign:001 20220809 1(integer) 0127.0.0.1:6379> setbit user:sign:001 20220820 1(integer) 0# 查看20220801是否签到了 1表示签到了 0表示没有签到127.0.0.1:6379> getbit user:sign:001 20220801(integer) 1127.0.0.1:6379> getbit user:sign:001 20220802(integer) 0# 统计用户签到的次数127.0.0.1:6379> bitcount user:sign:001 (integer) 4# 查看第一次签到的时间127.0.0.1:6379> bitpos user:sign:001 1(integer) 20220801
geo是Redis用来处理位置信息的。在Redis3.2中正式使用。
应用场景:
记录地理位置计算距离查找"附近的人"7.2、geo地理位置命令命令罗列
命令 | 帮助 | 描述 |
geoadd | geoadd key 经度 纬度 成员名称1 经度1 纬度1 成员名称2 | 添加地理坐标 |
geohash | geohash key 成员名称1 成员名称2 | 返回标准的geohash串 |
geopos | geopos key 成员名称1 成员名称2 | 返回成员经纬度 |
geodist | geodist key 成员1 成员2 单位 | 计算成员间距离 |
georadiusbymember | georadiusbymember key 成员 值单位 count 数asc[desc] | 根据成员查找附近的成员 |
# 添加坐标127.0.0.1:6379> geoadd user:addr 116.21 40.00 zhangsan 116.23 49.9 lisi(integer) 2# 获取坐标的hash127.0.0.1:6379> geohash user:addr zhangsan lisi1) "wx4es3v8ck0"2) "y8feuuh0e60"# 获取坐标的经纬度127.0.0.1:6379> geopos user:addr zhangsan1) 1) "116.21000200510025024" 2) "39.99999991084916218"# 计算两个用户的距离 单位米127.0.0.1:6379> geodist user:addr zhangsan lisi"1101141.4665"# 计算两个用户的距离 单位千米127.0.0.1:6379> geodist user:addr zhangsan lisi km"1101.1415"# 计算张三1200km之内的人的经纬度,距离,由近到远排出顺序127.0.0.1:6379> georadiusbymember user:addr zhangsan 1200 km withcoord withdist count 3 asc1) 1) "zhangsan" 2) "0.0000" 3) 1) "116.21000200510025024" 2) "39.99999991084916218"2) 1) "lisi" 2) "1101.1415" 3) 1) "116.23000055551528931" 2) "49.89999975254306719"
stream是Redis5.0后新增的数据结构,用于可持久化的消息队列。
应用场景,没有使用第三方消息队列,但是使用了redis,redis实现了消息队列功能,但是没有专门左中间件的成熟。所以需要谨慎选择。学习一下还是不错的。
8.2、stream类型命令命令罗列
命令 | 帮助 | 描述 |
xadd | xadd key id <*> field1 value1 | 将指定消息数据追加到指定队列(key)中,*表示最新生成的id(当前时间 序列号) |
xread | xread [COUNT count] [BLOCKmilliseconds] STREAMS key[key ...] ID [ID ...] | 从消息队列中读取,COUNT:读取条数,BLOCK:阻塞读(默认不阻塞)key:队列名称 id:消息id |
xrange | xrange key start end [COUNT] | 读取队列中给定ID范围的消息 COUNT:返回消息条数(消息id从小到大) |
xrevrange | xrevrange key start end [COUNT] | 读取队列中给定ID范围的消息 COUNT:返回消息条数(消息id从大小到大) |
xdel | xdel key id | 删除队列的消息 |
xgroup | xgroup create key groupname id | 创建一个新的消费组 |
xgroup | xgroup destory key groupname | 删除指定消费组 |
xgroup | xgroup delconsumer key groupname cname | 删除指定消费组中的某个消费者 |
xgroup | xgroup setid key id | 修改指定消息的最大id |
xreadgroup | xreadgroup group groupname consumer COUNT streams key | 从队列中的消费组中创建消费者并消费数据(consumer不存在则创建) |
命令操作
# 创建消息127.0.0.1:6379> xadd topic:001 * name zhangsan age 20"1661008860267-0"127.0.0.1:6379> xadd topic:001 * name wangwu age 24 name lisi age 35"1661008909085-0"# 查看消息127.0.0.1:6379> xrange topic:001 - 1) 1) "1661008860267-0" 2) 1) "name" 2) "zhangsan" 3) "age" 4) "20"2) 1) "1661008909085-0" 2) 1) "name" 2) "wangwu" 3) "age" 4) "24" 5) "name" 6) "lisi" 7) "age" 8) "35"# 读取一个消息127.0.0.1:6379> xread count 1 streams topic:001 01) 1) "topic:001" 2) 1) 1) "1661008860267-0" 2) 1) "name" 2) "zhangsan" 3) "age" 4) "20"# 创建一个消费组127.0.0.1:6379> xgroup create topic:001 group1 0OK# 使用消费组消费数据127.0.0.1:6379> xreadgroup group group1 user1 count 1 streams topic:001 >1) 1) "topic:001" 2) 1) 1) "1661008860267-0" 2) 1) "name" 2) "zhangsan" 3) "age" 4) "20"# 使用消费组消费数据 继续消费 总共两条127.0.0.1:6379> xreadgroup group group1 user1 count 1 streams topic:001 >1) 1) "topic:001" 2) 1) 1) "1661008909085-0" 2) 1) "name" 2) "wangwu" 3) "age" 4) "24" 5) "name" 6) "lisi" 7) "age" 8) "35"# 消费完了,没有啦127.0.0.1:6379> xreadgroup group group1 user1 count 1 streams topic:001 >(nil)
redis的功能之所以这么强大,也与它的各种数据类型有关,不同的业务场景可以使用不同的数据类型,从而更加高效的实现需求。
10、相关文章本人还写了Redis的其他相关文章,有兴趣的可以点击查看!
<<Redis弱事务性与Lua脚本原子性分析>><<Redis持久化机制分析>><<Redis的事件处理机制分析>><<Redis客户端和服务端如何通信?>><<Redis的淘汰机制分析>><<Redis的底层数据结构分析>><<Redis的8种数据类型,什么场景使用?>><<缓存是什么?缓存有哪些分类?使用它的代价是什么?>><<缓存的6种常见的使用场景>>,