API
通用命令
keys
:遍历所有key,筛选出复合条件的key,复杂度是*
:零个或多个任意字符?
:一个任意字符[a-z]
:a到z中匹配的字符
dbsize
:查看当前所有数据库中所有key的个数,复杂度是exists
:判断key是否存在,复杂度是- 存在返回1
- 不存在返回0
del
:根据key删除指定的键值对,也可同时指定多个key一起删除,复杂度是expire
:设置指定key的过期时间,单位秒,复杂度是ttl
:查看指定key的过期时间,复杂度是- 未过期返回还能存活多久的时间,单位秒
- 已过期返回-2
- 未设置过期时间返回-1
persist
:删除指定key的过期时间设置,复杂度是type
:返回key的value所对应的数据类型,复杂度是- key不存在返回none
- key存在返回对应的类型(全小写)
String数据类型
结构
-
虽说是字符串,但是在使用不同命令进行操作时内部可以转换成对应的数字、二进制数组
-
存储的最大限制是512MB
命令
get
:根据key获取value,复杂度是- 若key不存在会返回nil,代表空
set
:设置key和value,复杂度是- 若key不存在会添加,若key存在会覆盖
- 衍射出的子命令:key和value在中间位置,即nx和xx是后缀
set nx
:若key存在则设置失败,即添加操作,也可写成setnx
set xx
:若key不存在则设置失败,即更新操作
mget
:批量根据key获取value,复杂度是- 是原子操作
- m与批量操作的个数有关由,所以由于网络延时的原因,合理使用该命令会比单个使用
get
命令效率高
mset
:批量设置key和value,复杂度是- 是原子操作
- m与批量操作的个数有关,所以由于网络延时的原因,合理使用该命令会比单个使用
set
命令效率高
getset
:为key设置新的value,同时返回旧的value,复杂度是- 是原子操作
整型数字操作
incr
:指定key自增1,复杂度是- 若key不存在会创建一个value为1的key
- 若value有非数字的字符会报错,包括小数点
decr
:指定key自减1,复杂度是- 若key不存在会创建一个value为-1的key
- 若value有非数字的字符会报错,包括小数点
incrby
:指定key自增指定步长,复杂度是- 若指定步长为负数就是递减了
- 若key不存在会创建一个value为步长的key
- 若value有非数字的字符会报错,包括小数点
decrby
:指定key自减指定步长,复杂度是- 若指定步长为负数就是递增了
- 若key不存在会创建一个value为负步长的key
- 若value有非数字的字符会报错,包括小数点
浮点型数字操作
incrbyfloat
:指定key自增指定步长,可以指定步长为小数,复杂度是- 若指定步长为负数就是递减了
- 若key不存在会创建一个value为步长的key
- 若value有非数字的字符会报错,不包括小数点
字符串操作
append
:指定key的value后追加字符串,复杂度是strlen
:指定key的value中字符串的长度,复杂度是- 注意:一个中文字符会占用两个长度
getrange
:获取key的value某指定范围子串,复杂度是- 下标从0开始,闭区间
- 负数倒着数
setrange
:设置key的value某指定位置开始,向后偏移的覆盖为指定内容,复杂度是- 下标从0开始
- 负数倒着数
使用场景
存储对象方案一
将整个对象进行序列化或标准化为JSON、XML,将key做为对象的ID
-
优点:访问Redis编程简单,节约内存
-
缺点:序列化开销,修改属性需要操作字符串整个数据
存储对象方案二
将key为对象的业务ID+属性名,对各个属性分散存储,比如:user:name
,使用冒号分隔
- 优点:Redis数据直观可查,可部分属性更新,比较方便
- 缺点:内存占用较大,key较为分散
Hash数据类型
结构
对应着一个Map集合,该Map集合的key称之为field,value还是value,并且这个集合中的field和value只能存储字符串数据类型
Map
field value
+--------+--------+
| field1 | value1 |
key ----> | field2 | value2 |
| field3 | value3 |
| ... | ... |
+--------+--------+
命令
hget
:获取指定key的field对应的value,复杂度是hset
:设置指定key的field对应的value,复杂度是hsetnx
:若field存在则设置失败,即添加操作
hdel
:删除指定key的field对应的value,也可同时指定多个field一起删除,复杂度是- 若删除到整个Map都为空时,这个key也会被删除
hmget
:批量获取指定key的field,复杂度是- 是原子操作
- m与批量操作的个数有关
hmset
:批量设置指定key的field的value,复杂度是- 是原子操作
- m与批量操作的个数有关
hexists
:判断指定key的field是否存在,复杂度是- 存在返回1
- 不存在返回0
hlen
:获取指定key的field的个数,复杂度是
遍历操作
hgetall
:获取所有field和value,复杂度是- m与field个数有关
hvals
:获取所有的value,复杂度是- m与field个数有关
hkeys
:获取所有的key,复杂度是- m与field个数有关
整型数字操作
hincrby
:指定key的field的value自增指定步长,复杂度是- 若field不存在会创建一个value为步长的field
- 若key不存在会先创建key,再创建field
- 若指定步长为负数就是递减了
- 若value有非数字的字符会报错,包括小数点
- 若field不存在会创建一个value为步长的field
浮点数字操作
hincrbyfloat
:指定key的field的value自增指定步长,可以指定步长为小数,复杂度是- 若field不存在会创建一个value为步长的field
- 若key不存在会先创建key,再创建field
- 若指定步长为负数就是递减了
- 若value有非数字的字符会报错
- 若field不存在会创建一个value为步长的field
使用场景
存储对象
将对象属性在field中,将key做为对象的ID
-
优点:Redis数据直观可查,可部分属性更新,比较方便,节约内存(底层到一定程度会该为压缩Map编码格式)
-
缺点:访问Redis编码稍微比较复杂,属性过期时间不好控制(需要自己逻辑实现)
List数据类型
结构
- 有序,有重复元素
- 有独特的负索引
[ a, b, c, d] : 元素列表
[ 0, 1, 2, 3] : 正索引
[-4, -3, -2, -1] : 负索引,即倒数第几个,从1开始
命令
增加
rpush
:在指定key的右面添加一个或多个元素,复杂度是到,m取决于要添加的个数- 插入多个元素时,从左向右依次添加到右面
lpush
:在指定key的左面添加一个或多个元素,复杂度是到,m取决于要添加的个数- 插入多个元素时,从左向右依次添加到左面
linsert
:在指定key的指定元素前面或后面插入元素,需要遍历整个列表,复杂度是before
:前面插入after
:后面插入
删除
若删除到整个List都为空时,这个key也会被删除
rpop
:从指定key的右面删除一个元素,复杂度是lpop
:从指定key的左面删除一个元素,复杂度是lrem
:从指定key中删除指定个数的与之匹配的元素,复杂度是count
等于0:全部删除count
是正数:从左往右删除count个count
是负数:从右往左删除count个
ltrim
:将指定key中的列表修剪为指定索引范围内(闭区间)的子列表,复杂度是brpop
:阻塞的从指定key的右面删除一个元素,即若列表为空时会等待到有值时才会弹出,复杂度是timeout
:设置的阻塞超时时间,单位秒,若设置为0,代表用不阻塞
blpop
:阻塞的从指定key的左面删除一个元素,即若列表为空时会等待到有值时才会弹出,复杂度是timeout
:设置的阻塞超时时间,单位秒,若设置为0,代表用不阻塞
修改
lset
:设置指定key下指定索引的元素内容,复杂度是
查询
lrange
:获取指定key的指定索引范围内(闭区间)的所有元素,复杂度是lrange key 0 -1
:遍历整个列表
lindex
:获取指定key的指定索引下的元素,复杂度是llen
:获取指定key的列表长度,复杂度是
使用场景
- 栈:使用
lpush
和lpop
- 队列:使用
lpush
和rpop
- 固定容量的容器集合:使用
lpush
和ltrim
- 消息队列:使用
lpush
和brpop
Set数据类型
结构
- 无序,无重复元素
- 支持集合间的操作
命令
集合内的操作
sadd
:向指定key中添加元素(可添加多个),若元素已存在则不会添加进去,复杂度是srem
:将指定key中的元素删除(可删除多个),复杂度是sismember
:判断元素是否存在集合中,存在返回1,不存在返回0,复杂度是srandmember
:获取指定key中随机的一个或多个元素,个数可以指定,复杂度是- 指定个数为正数:一次性获取过多时,不会超过集合中元素个数
- 指定个数为负数:一次性获取过多时,可以超过集合元素个数
spop
:将指定key中元素随机删除一个或多个,个数可以指定,且不允许为负数,复杂度是smembers
:获取指定key中的所有元素,复杂度是,m取决于集合中元素的个数scard
:获取指定key中元素的个数,复杂度是
集合间的操作
sdiff
:返回指定key的差集,可指定多个key,若只有一个则返回key集合本身sdiffstore
:从第二个key开始计算,不返回结果,将结果存储在第一个key中
sinter
:返回指定key的交集,可指定多个key,若只有一个则返回key集合本身sinterstore
:从第二个key开始计算,不返回结果,将结果存储在第一个key中
sunion
:返回指定key的并集,可指定多个key,若只有一个则返回key集合本身sinterstore
:从第二个key开始计算,不返回结果,将结果存储在第一个key中
使用场景
抽奖系统
将参与的用户添加到集合中,在使用spop
或srandmember
获取获奖用户
赞踩系统
将赞或踩过的用户添加到该消息的赞踩集合中,使用集合间操作sinter
,就可以得到共同爱好的用户
标签系统
给用户添加标签,使用sadd
,将标签添加到用户集合中
给标签添加用户,使用sadd
,将用户添加到标签集合中
ZSet数据类型
结构
- 有序,无重复元素
- 每个元素都多存储着一个分数信息,是根据分数来排序的,从小到大
Map
value key
| |
\|/ \|/
score element
+--------+----------+
| score1 | element1 |
key ----> | score2 | element2 |
| score3 | element3 |
| ... | ... |
+--------+----------+
命令
集合内的操作
zadd
:向指定key中添加分数和元素(可添加多对),若元素已存在则不会添加进去,复杂度是zrem
:将指定key中的元素删除(可删除多个),复杂度是zscore
:获取指定key中指定元素的分数,复杂度是zrank
:获取指定key中元素的从高到底排名,排名从零开始,复杂度是zrevrank
:获取指定key中元素的从低到高排名,排名从零开始,复杂度是zincrby
:将指定key中指定元素的分数自增指定步长,复杂度是- 若指定步长为负数就是递减了
- 若element不存在会创建一个score为步长的key
- 若key不存在会先创建key,再创建element
- 若value有非数字的字符会报错,不包括小数点
zcard
:获取指定key中元素的个数,复杂度是
范围操作
zrange
:获取指定key的指定排名(排名从零开始)范围内(闭区间)的所有元素(升序),复杂度是,n是指有序集合中的元素个数,m是指范围内的元素个数withscores
:若加此后缀参数后,元素分数也会对应返回zrange key 0 -1
:遍历整个有序集合zrange key 0 -1 withscores
:遍历整个有序集合,包括分数
zrevrange
:降序的zrange
zrangebyscore
:获取指定key的指定分数范围内(闭区间)的所有元素(升序),复杂度是,n是指有序集合中的元素个数,m是指范围内的元素个数withscores
:若加此后缀参数后,元素分数也会对应返回
zrevrangebyscore
:降序的zrangebyscore
zcount
:获取指定key的指定分数范围内(闭区间)的元素个数,复杂度是,n是指有序集合中的元素个数,m是指范围内的元素个数zremrangebyrank
:删除指定key的指定排名范围(闭区间)的元素,复杂度是,n是指有序集合中的元素个数,m是指范围内的元素个数zremrangebyscore
:删除指定key的指定分数范围(闭区间)的元素,复杂度是,n是指有序集合中的元素个数,m是指范围内的元素个数
集合间的操作
zunionstore
:返回指定key的并集(必须指定要操作的key的个数),可指定多个key,从第二个key开始计算,将结果存储在第一个key中withscore
:设置乘法因子,默认都是1,若有重复key在合并时,是将两个相同的元素的分数进行相加,若还需要乘上一个数在相加就需要在该参数中设置
zinterstore
:返回指定key的交集(必须指定要操作的key的个数),可指定多个key,从第二个key开始计算,将结果存储在第一个key中withscore
:设置乘法因子,默认都是1,重复key在合并时,是将两个相同的元素的分数进行相加,若还需要乘上一个数在相加就需要在该参数中设置
使用场景
排行榜
使用zadd
进行分数添加、zincrby
进行分数添加、zrem
进行删除,对于这些最核心的就是分数使用什么表示
- 更新榜:使用时间戳作为分数
- 点赞榜:使用点赞量即可
- 月榜周榜日榜:使用日榜进行并集汇总
Bitmap数据结构
结构
其实就是字符串,每个字符都是以ASCII进行编码,位图提供了一种操作字符串中单个二进制位的API,对于这些API来说复杂度是,m取绝于字符串中二进制位的个数
命令
getbit
:获取字符串中的指定索引的二进制位- 若超过字符串二进制位数长度,会返回0
setbit
:设置字符串中的指定索引的二进制位,只能设置0和1- 若key不存在会创建key
- 若超过字符串二进制位数长度,会在前面自动补零
bitcount
:获取指定key中二进制位为1的个数- 可指定范围,注意范围说的是字节范围,8个二进制位为一个字节,闭区间,索引从0开始
bitop
:从第二个key开始做位运算,结果存放到第一个key中,返回结果key的字节长度and
:与or
:或not
:非xor
:异或
bitpos
:获取指定key中,从左到右,第一个为0或1的二进制位索引- 可指定范围,注意范围说的是字节范围,8个二进制位为一个字节,闭区间,索引从0开始
使用场景
用户统计
将所有用户都与一个索引对应(用户ID),将赞或踩过的用户对应的索引位置为1
相比set,若要记录的用户越多则该方式越省内存,反之则会更浪费内存,因为set至少需要一个整型(32位)来记录一个用户,bitMap只需要一个二进制位,若用户ID很大会导致一个用户会使用很大的索引导致索引偏后,前面二进制位都是无用的内容
要注意,Redis中一个字符串的最大容量是512MB,并且在位操作时也比较耗时
HyperLogLog数据结构
结构
基于HyperLogLog算法,极小空间完成独立数量统计的数据结构,本质还是字符串
- 不会有重复元素
- 有错误率,错误率为0.81%
- 无法该结构内元素对单个用户进行判断是否已经存入
命令
pfadd
:向指定key中添加元素(可添加多个),添加正常会返回1,而不是添加成功的个数pfcount
:返回指定key中的元素个数pfmerge
:从第二个key开始进行合并,合并后的结果存放到第一个key中
使用场景
只需要统计用户数,不关心其他问题,并且可以容忍错误率
GEO数据结构
结构
基于ZSet实现,所以可以使用ZSet的所有命令
命令
geoadd
:向指定key中添加经纬度和地名(可添加多对),地名不会重复,仅仅其标识作用geopos
:获取指定key下的指定地名的经纬度geodist
:计算指定key下的两个地名之间的距离unit
:指定距离单位,m
、km
、mi
(英尺)、ft
(尺),默认是m
georadius
:获在指定key中某个地理位置在一定范围内(需要指定单位)的地理位置信息集合withcoord
:返回包含经纬度withdist
:返回包含距中心节点的距离,单位与指定的一致withhash
:返回结果中包含geohash(52位有符号整数)count
:返回指定数量结果asc|desc
:返回结果按照距离中心位置升序或降序store
:将返回结果的位置信息保存在指定键中storedist
:将距离保存在指定的键中
使用场景
存储地理信息,计算距离,范围等
发布订阅
命令
publish
:向指定频道发送消息(频道就是key),返回订阅者的数量subscribe
:订阅频道(可同时订阅多个频道)psubscribe
:模式订阅,可使用通配符进行多个频道的订阅
unsubscribe
:取消订阅(可同时取消订阅多个频道)punsubscribe
:模式取消订阅,可使用通配符进行多个频道的订阅
pubsub channels
:返回至少有一个订阅者的频道pubsub numsub
:列出指定频道的订阅者数量
消息格式
-
首次开始监听订阅消息时的三行内容:
- 固定内容subscribe,即刚才执行的命令
- 频道的名称,即刚才执行命令的参数
- 固定内容返回1
-
之后的接收的消息时的三行内容:
- 固定内容message
- 频道的名称
- 收到的新消息
代码
Java
发布者
import redis.clients.jedis.Jedis;
public class Main {
public static void main(String[] args) {
Jedis jedis = null;
try {
jedis = new Jedis("127.0.0.1", 6379);
jedis.auth("redis"); //操作数据前设置的密码
jedis.publish("channel", "hello");
} finally {
if (jedis != null) {
jedis.close();
//3. 关闭连接
}
}
}
}
订阅者
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class Main {
public static void main(String[] args) {
Jedis jedis = new Jedis("122.51.213.160", 6379);
jedis.auth("redis"); //操作数据前设置的密码
/**
* Jedis对象的subscribe()方法接收两个参数
* JedisPubSub jedisPubSub :用来写监听接收到消息的监听函数,无法使用lambda表达式
* 需要实现内部的onMessage()方法,监听函数会阻塞掉当前线程的运行
* String channel :接收到是那个频道的消息
* String message :接收到的消息
* String... channels :所监听的频道,是个可变参数,所以可以同时监听多个频道
*/
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("接收到 " + channel + " 频道发送的:" + message);
}
}, "channel");
}
}
Node
发布者
const redis = require("redis"); //导入redis模块
const client = redis.createClient(6379, "122.51.213.160", {
password: "redis"
}); //获取redis连接对象
client.on("error", function (err) { //监听连接出错
throw err;
});
client.once("connect", () => { //监听连接建立成功
client.publish("testPublish", "message"); //向指定频道发布消息
client.quit(() => console.log("关闭连接")) //关闭连接
})
订阅者
const redis = require("redis"); //导入redis模块
const client = redis.createClient(6379, "122.51.213.160", {
password: "redis"
}); //获取redis连接对象
client.on("error", function (err) { //监听连接出错
throw err;
});
client.once("connect", () => { //监听连接建立成功
client.subscribe('testPublish'); //订阅频道
})
client.on('message', function (channel, msg) { //监听以订阅频道消息
console.log(channel, ":", msg);
});
Comments NOTHING