redis数据类型
redis数据类型
键 - key
在了解数据类型之前,先了解一下 redis 的键。
在 redis 中 命令不区分大小写,但是注意 redis 中的 key 和 value 是区分大小写的。
字符串 - string
字符串数据结构是简单的 K-V 模式数据结构。
特点
- 单值单 value。
- 二进制安全,可以包含任何数据。
- 一个键对应 value 值最大能存储数据 512 MB。
常用命令
- 设置字符串 -
set test 100
- 查询字符串 -
get test
- 删除字符串 -
del test
- 追加字符串 -
append test
- 查询字符串长度 -
strlen test
- 批量添加 -
mset A 1 B 2
- 批量获取 -
mget A B
- 先查询再设置 -
getset hello world
自增自减命令
由于 redis 是基于单线程的,这些增减命令都具有原子性。
注意命令只能操作 value 是数字的 key 值。
- 自增1 -
incr count
- 自减1 -
decr count
- 自增指定值 -
incrby count 10
- 自减指定值 -
decrby count 10
incr 和 decr 命令应用场景很广泛,可用于点赞数量统计等场景。
- 查询字符串指定区间 -
getrange key start end
- 设置字符串指定区间 -
setrange key offset value
- 设置可过期字符串(秒) -
setex key seconds value
- 值不存在可设置 -
setnx key value
- 批量设置值不存在可设置 -
msetnx key value [key value ...]
实战总结
点赞数量
新增点赞
incr read
点赞总数
get read
文章阅读量
列表 - list
list 是类似双端链表或双端队列的数据结构。
特点
- 类似双向链表或双端队列,可以在列表左右两边操作数据。
- 单值对应多 value。
- 列表是有序的,按照 value 插入数据对 value 排序。
- 列表存放的 value 可重复。
常用命令
- 列表左边增加元素 -
lpush key element [element ...]
- 列表右边增加元素 -
rpush key element [element ...]
- 列表左边删除元素 -
lpop key
- 列表右边删除元素 -
rpop key
- 遍历列表(开始~结束) -
lrange key start stop
- 获取列表指定位置元素 -
lindex key index
- 查询列表长度 -
llen key
- 删除多个相同 value -
lrem key count element
- 截取列表重新赋值 -
ltrim key start stop
- 从源列表右边提取元素放到目的列表 -
rpoplpush source destination
- 修改列表指定位置 value -
lset key index element
- 在列表指定位置前或后添加元素 -
linsert key BEFORE|AFTER pivot element
实战总结
- 公众号文章订阅
新增文章
lpush code java css
获取推送的最近5篇文章
lrange code 0 4
哈希 - hash
hash 的数据结构也是 K-V 模式,但是 hash 的 V 对应 K-V,也就是 K-(K-V),适合存储对象。比如存储用户信息,K 是用户Id,V 是用户信息。
特点
- 数据结构特点是 K -(K-V),K 和 V 都是字符串类型。
常用命令
- 添加元素 -
hset key field value [field value ...]
- 获取元素-
hget key field
- 向哈希表批量添加元素 -
hmset key field value [field value ...]
- 批量获取哈希表元素 -
hmget key field [field ...]
- 获取哈希表所有元素 -
hgetall key
- 删除哈希表中的元素 -
hdel key field [field ...]
- 获取哈希表长度 -
hlen key
- 判断哈希表中是否存在某个 key -
hexists key field
- 获取哈希表所有 key -
hkeys key
- 获取哈希表指定 key 的所有 value -
hvals key
- 增加哈希表指定 key 的 value(value 必须是数值,增加整数)-
hincrby key field increment
- 增加哈希表指定 key 的 value (value 必须是数值,支持浮点数)-
hincrbyfloat key field increment
- 对哈希表某个 key 赋值(key 值不存在进行赋值,key 值存在此命令无效)-
hsetnx key field value
实战总结
- 购物车
添加商品
hset shopcart 10001 1
增加商品数量
hincreby shopcart 10001 1
统计购物车商品总数
hlen shopcar
删除商品
hdel shopcart 10001
获取购物车列表
hgetall shopcart
无序集合 - set
set 是一种无序集合,存储元素无序并且不可重复。
特点
- 单值对应多 value。
- set 集合存放元素是无序的。
- set 集合存放的元素是不可重复的。
常用命令
- 添加元素 -
sadd key member [member ...]
- 遍历集合元素 -
smembers key
- 判断某个元素是否存在集合中 -
sismember key member
- 获取集合中元素个数 -
scard key
- 删除集合元素 -
srem key member [member ...]
- 从集合从随机获取几个数(不删除)-
srandmember key [count]
- 集合元素随机出栈 -
spop key [count]
- 将一个集合内的某个值赋给另一个集合 -
smove source destination member
数据集合类
- 差集 -
sdiff key [key ...]
- 交集 -
sinter key [key ...]
- 并集 -
sunion key [key ...]
实战总结
景点预约功能
- 新增预约
- 取消预约
- 判断用户是否预约过
- 统计预约总人数
- 展示预约用户信息
抽奖功能
参加抽奖
统计参加人数
随机抽两个人(不限次数)
srandmember key [count]
随机抽两人(只能中一次)
spop key [count]
微博共同关注的人
对两个用户关注的人取交集
sinter userA userB
QQ - 可能认识的人
对两个用户取差集
sdiff userA userB
有序集合 - zset
zset 是有序版本,是在 set 集合的基础上,增加一个 score 值,来进行排序。
特点
- 数据结构是
k v1 score1 v2 score2
- zset 集合存放元素是有序的。
- zset 集合存放元素也是不可重复的。
常用命令
添加元素 -
zadd key [NX|XX] [CH] [INCR] score member [score member ...]
遍历元素(可选是否显示分数) -
zrange key start stop [WITHSCORES]
删除集合中某个元素 -
zrem key member [member ...]
根据分数过滤元素 -
zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
可以选择展示分数(withscores)和限制元素个数(limit)。
对集合中某个元素进行增量 -
zincrby key increment member
获取集合中元素总个数 -
zcard key
获取集合指定分数区间的元素个数 -
zcount key min max
获取集合中指定元素的下标 -
zrank key member
获取集合中指定元素的分数 -
zscore key member
倒序遍历集合区间 -
zrevrange key start stop [WITHSCORES]
倒序获取集合中某个元素的下标 -
zrevrank key member
按照倒序根据分数过滤元素 -
zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]
从最大值到最小值过滤,可以选择展示分数(withscores)和限制元素个数(limit)。
实战总结
销售排行榜
增加商品销量
zincrby book 1 java
查询前十条销售量的商品
zrevrange book 0 9 WITHSCORES
微博热搜排行榜
添加新闻初始热度
zadd weibo 250000 test
点击增加热度
zincrby weibo 1 test
查询前十条热度最高的新闻
zrevrange weibo 0 9 WITHSCORES
位图 - bitmaps
bitmaps 又称位图,本身并不是一种实际的数据结构,而是基于 String 数据类型的按位操作。bitmaps 本质上是数组,数组由多个二进制位组成,每个二进制位只能存储 0 和 1。
特点
- 优点
位图数据结构操作二进制位,只有 0 和 1 两个值。
只支持存储 0 和 1,不支持存储其它数据类型。
基于 String 数据类型,bitmaps 最大存储长度为 512 MB。
由于 String 数据类型的数据结构为 SDS (简单动态字符串),SDS 最大长度为 512MB,所以 bitmaps 的最大长度是 512MB。
由于 Bitmaps 是按位操作,所以存储时可以极大的节省空间。
512MB (2^32)内存可以存储将近 42.9 亿的字节信息。
- 缺点
由于 Bitmaps 是按位操作,当二进制位的偏移量很大时,会比较耗时。
Bitmaps 有时可能会浪费空间。
Bitmaps 底层基于 SDS,底层字符串可以根据输入的位次,进行扩展以保存 value 到指定偏移量,对应的空白位置以 0 填充。
若 Bitmaps 操作大的 offset 时,对内存的分配可能阻塞 Redis 服务器。
如果连续输入比较稀疏(输入1,30000等跨度比较大的位次),会浪费大量内存空间。
常用命令
向指定偏移量 bit 位置设置值 -
setbit key offset value
当 key 不存在时,自动生成一个新的字符串。
java127.0.0.1:6379> set hello big OK 127.0.0.1:6379> getbit hello 7(integer) 0127.0.0.1:6379> setbit hello 7 1(integer) 0127.0.0.1:6379> get hello "cig"127.0.0.1:6379> 127.0.0.1:6379> setbit world 50 1(integer) 0127.0.0.1:6379> get world "\x00\x00\x00\x00\x00\x00 "127.0.0.1:6379> setbit world 50 0(integer) 1127.0.0.1:6379> get world "\x00\x00\x00\x00\x00\x00\x00"127.0.0.1:6379>
offset 参数值必须大于等于 0,小于 2^32。
获取位图指定 bit 的值 -
getbit key offset
使用 getbit 命令获取 String 类型指定 bit 的值。
java127.0.0.1:6379> set hello big OK 127.0.0.1:6379> getbit hello 2(integer) 1127.0.0.1:6379>
统计位图指定区间中 bit 为 1 的总数量 -
bitcount key [start end]
java127.0.0.1:6379> setbit hello 10 1(integer) 0127.0.0.1:6379> setbit hello 15 1(integer) 0127.0.0.1:6379> bitcount hello (integer) 2127.0.0.1:6379>
对一个或多个 key 执行逻辑操作(与、非、或、异或) -
bitop operation destkey key [key ...]
【BITOP】支持逻辑操作,包含 且 AND、或 OR、异或 XOR、非 NOT;
- 且 AND(&):同 1 为 1,其余为 0;
- 或 OR(|):有 1 为 1,同 0 为 0;
- 异或 XOR(^):不同为 1,相同为 0;
- 非NOT(~):1 变 0,0 变 1;
javaA 二进制 01000001B 二进制 01000010@ 二进制 01000000127.0.0.1:6379> set a A OK 127.0.0.1:6379> set b B OK 127.0.0.1:6379> 127.0.0.1:6379> 127.0.0.1:6379> 127.0.0.1:6379> bitop and ggg a b (integer) 1127.0.0.1:6379> get ggg "@"127.0.0.1:6379>
查询指定字节区间第一个指定 bit (0 或 1)的位置 -
bitpos key bit [start] [end]
。java127.0.0.1:6379> setbit hello 0 1(integer) 0127.0.0.1:6379> setbit hello 1 1(integer) 0127.0.0.1:6379> setbit hello 2 0(integer) 0127.0.0.1:6379> bitpos hello 0(integer) 2127.0.0.1:6379> bitpos hello 1(integer) 0127.0.0.1:6379>
实战总结
用户每月签到
用户签到
setbit signIn:YYYYMM:userId day 1
统计当月签到总数
bitcount signIn:YYYYMM:userId
代码如下:
java@Service public class Bitmaps_SignInService { @Autowired RedisUtil redisUtil; @Autowired RedisTemplate redisTemplate; private final String SIGNIN = "signIN"; /** * 用户签到 */ public boolean signIn(String userId) { //当月 String month = LocalDateTimeUtils.formatNow(LocalDateTimeUtils.YEAR_MONTH); //本月第几天 int dayOfMonth = LocalDateTime.now().getDayOfMonth(); return redisUtil.setBit(getSignInKey(userId, month), dayOfMonth, true); } /** * 获取指定用户某月份签到总数 */ public int countMonthSignIn(String userId, String month) { String signInKey = getSignInKey(userId, month); //redisTemplate没有提供bitcount命令,可使用execute调用相关方法 Long execute = (Long) redisTemplate.execute( (RedisCallback<Long>) con -> con.bitCount(signInKey.getBytes())); if (Objects.isNull(execute)) { return 0; } return execute.intValue(); } private String getSignInKey(String userId, String month) { return SIGNIN + ":" + month + ":" + userId; } }
测试例子如下:
java/** * bitmaps-用户签到 */ @Test public void bitmapsTest() { String userId = "xiaoming"; //签到 boolean signInFlag = bitmapsSignInService.signIn(userId); System.out.println(userId + " => 签到状态:" + signInFlag); String month = LocalDateTimeUtils.formatNow(LocalDateTimeUtils.YEAR_MONTH); int signInCount = bitmapsSignInService.countMonthSignIn(userId, month); System.out.println(userId + " => " + month + " => 签到次数为:" + signInCount); } //output xiaoming => 签到状态:false xiaoming=>2021-08=> 签到次数为:1