redis简介
- 相比如mysql,redis也可以当作数据库来使用,而且更快,因为是内存中的数据库。但是和mysql相比,具有存储空间小
的问题,因为内存空间远小于硬盘空间,同时也是因为这个问题,redis的功能相比mysql要少,比如不存在多表查询等等操作 - “二八原则”:20%的数据满足80%的访问需求,典型的方案:redis结合mysql使用,使用redis存储经常使用的热点数据,剩下的数据存储在mysql中,只在需要的时候去取。其中涉及系统中复杂度的增加、redis和mysql数据的同步问题等
- redis最初是想作为一个消息队列(实现分布式系统中的生产者、消费者模型)
- msyql数据库的主从分离与读写分离:读的需求是要远大于写的需求的,所以只有主库接受写的请求,并将发生改变的内容同步到从库,从库不负责处理写的请求,负责读的请求,上层也可以引入负载均衡的策略对读节点进行选择
redis存放、获取键值的操作
1. 存放键值对
(1) redis中,key都是字符串,value可以是各种类型。存放键值对,使用set keyname keyvalue;redis不区分大小写,也不需要
注意单双引号的问题,写不写都可以。
(2) set keyname value [ex seconds | px milliseconds] [nx|xx],ex指定超时时间以秒为单位,px以毫秒为单位;nx表示有设置keyname则不插入,xx表示只在keyname存在时修改value
(3) mset keyname value [keyname value] 设置多组键值对
(4) setnx setex psetex即设置时就加上选项,setnx表示只在不存在时设置,setex表示设置过期时间,秒为单位,psetex也是设置过期时间,但是以毫秒为单位
2. 获取键值对
(1) redis中,获取键值对使用get,通过get keyname的方式获取
(2) mget,获取多组键值对
获取键值对时的匹配原则
?表示任意一个字符,如key可由ke?检索出来*表示任意多个字符,使用其实和linux检索文件名时使用一样[abcdefg]表示从中括号中的选项中匹配任意一个[^e]表示不匹配e[a-c]表示范围匹配
但是实际开发中,几乎不会使用(禁止)*的方式,因为会检索整个redis中的所有key,而redis又是单线程的,
所以可能会导致该线程阻塞在检索的过程中,导致大量请求从redis的缓存数据中取不出结果,都去向数据库发出请求,
导致数据库压力过大挂掉
3. 查看键值对是否存在
查看一个键值对(多个)是否存在,使用exists keyname1 keyname2 ...
关于同时支持多个keyname的问题:redis是客户端、服务器形式的应用,所以对于服务器的请求操作都要通过网络进行,这意味着经由网络传输、各个层级之间协议的封装与解包,都是较大的时间消耗,所以redis支持一次请求携带多个key值去操作,以节省传输的时间(网络的速度一般网卡和硬盘速度对比还是网络慢很多的
4. 删除键值对
使用del删除键值对,del keyname1 keyname2
5. 设置过期时间
- 秒为单位,
expire keyname seconds - 毫秒为单位,
pexpire keyname microseconds
6. 查看存活时间
ttl(time to live) + keyname,查看剩余存活时间,如果没有设置过期时间,那么就返回-1;如果查无此key,
就返回-2
redis怎样删除已经过期的key呢?
- 定期删除。定期查看一部分key是否过期,这个过程很快(因为redis是单线程的,耗费时间过长就会导致类似于前面说的*通配符使用的问题
- 惰性删除,当一个key过期了,也不进行删除,而是在使用设个key的时候,发现这个key过期了,然后再删除
- redis其实并没有使用定时器的方式去删除过期的key,有些猜测是早期的redis是单线程的,便奠定了单线程的基调,后面也维持了这种风格,但是定时器的实现方案,也是值得了解的,有优先级队列和时间轮两种方式
优先级队列
- 将有过期时间的任务和过期时间放在一个根据过期时间建立的小根堆当中,根据堆顶元素的过期时间,去让
线程休眠一段时间,然后唤醒线程节省cpu资源;如果期间有新的事件进入队列,那么就再次唤醒线程检查是否需要
处理堆顶事件
时间轮
首先搭建一个环形队列,其中每个节点都指向一个链表的头节点,从头节点往后的每个节点都代表过期时间处在
某个范围的事件,让检测线程每个一段事件往后走一个检查该格中是否有需要处理的事件(结合周期和环形队列
循环的概念,不难得出一个链表中可能有多种时间),但是这种方式对于时间粒度和环形队列的长度的设计
都有很高的要求
7. 查看类型
使用type + keyname查看key对应的value的类型
redis数据类型与实现方式
很多类型,redis承诺对外是某种类型,但是具体实现的时候可能采用了其他的方式
1. string
(1) raw,就是字符串的形式存储
(2) int,如果字符串中存储的是数字的话,就直接作为数字存储
(3) embstr,对于短字符串做出优化的存储方式,也负责存储小数,这也意味着性能的损失,因为整数通过int的方式存储直接就可以
比较,但是通过embstr的话就要转化为数字之后再进行比较
2. hash
(1) hashtable,以redis自己的方式做的哈希表
(2) ziplist,压缩表,当value的类型是哈希表但是其中的元素又很少时,就可以采用ziplist来遍历(因为元素少所以时间差异不大)压缩表通过内部的优化,将数据按照更紧凑的方式进行表示,当数据增多时,会导致效率下降
3. list
(1) 以前的版本采用的是linkedlist + ziplist实现,redis3.2以后,采取quicklist的实现方式,类似于std::deque
4. set
(1) hashtable (2) intset整数集合,当集合中数据较少而且只存储整数的时候,就是用这种结构
5. zset
(1) skiplist,跳表,类似于链表,但是每个节点有多个指针域,使之能够实现logn的查询效率
(2) ziplist,元素个数比较少或者元素大小比较小
查看具体存储方式
object encoding keyname,查看某个value具体的存储方式
redis的单线程工作模型
- redis的客户端发送请求是并发的,但是redis服务器的核心工作逻辑是单线程的,这样请求也就再redis服务器上串行执行,
没有并发的问题 - 所以说一方面,如果一个操作阻塞过久,就可能导致redis服务端挂掉;另一方面,也不是所有业务场景都适合单线程,因为
redis需要处理的业务基本上都是短平快的,对于cpu并行的要求很低,也就可以采用单线程的方式处理核心业务
为什么说redis快,效率高呢?
- 首先redis效率高是和mysql这种关系型数据库相比,因为后者是对磁盘的操作,前者是对内存的操作,硬件上的操作速度
就差了几个数量级,因此redis自然更快 - redis提供的功能相对要少一些,比如mysql插入的时候如果有约束的话还要射击先查询的过程,查询的时候还有多表联查
等等操作,在功能和业务上的区别,也是造成差异的原因
string 类型
1. incr和incrby
(1) incr,表示给相应value + 1,只有实际类型是int的才可以
(2) incrby,表示给相应value + n,n必须是整数,可以是负数
(3) 如果key不存在,就从零开始处理
2. decr和decrby
(1) 除了进行的是减操作以外,其他的都是和incr与incrby一样的
3. incrbyfloat
可以进行小数和整数的操作,如果需要减操作,使用负数即可
4. append
(1) 对字符串进行追加操作,并返回追加之后的长度
(2) 对于redis来说,不会对我们的数据进行字符集上的处理,因此输入中文的话默认打出的就是原编码,所以可以在启动客户端
的时候加上–raw指令,让客户端尝试解读返回的二进制数据并展示,就能够完成中文的显示了
5. getrange
(1) getrange keyname start end,表示获取[start, end]的内容,以字节为单位,这意味着可能会出现中文被解析成乱码的情况
,因为无论是utf8还是gbk都是多字节编码一个中文字符
(2) 当end是负数时,表示倒数第几个字符,例如-1表示倒数第一个字符
(3) 根据两个端点的情况,redis会自动截取内容(数字同理),但是如果最后出现start > end时,会导致解析不出内容
6. setrange
(1) setrange key start value,设置从start开始的内容为value,具体设置到哪里取决于value的长度
(2) 如果设置的key不存在,那么就根据start的值,用空格填充前面的内容;如果start超过了当前内容的长度,也是同理往后
添加用空格补全长度
7. strlen
(1) 获取字符串类型的value的长度,单位是字节,对于中文也是具体字节而不是字符的个数
redis中的hash类型
redis中的hash,使用field-value表示键值的结构,其中,value的类型只允许是字符串
1. hset、hget、hexists、hdel
(1) hset keyname fieldname value,表示keyname用来查找这个哈希表,fieldname是哈希表的键值。
(2) hget keyname fieldname,获取keyname的哈希表的fieldname所对应的值
(3) hexists keyname fieldname,判断keyname对应的哈希表是否具有fieldname的键值
(4) hdel keyname fieldname,删除keyname对应的哈希表的fieldname键值
2. hkeys、hvals
hkeys key,获取key对应的哈希表中的所有field;hvals key,获取key对应的哈希表中的所有value值。尽量不要使用这些操作,
和keys*有异曲同工之妙
hlen、hsetnx、hincrby、hincrbyfloat
hlen keyname,用来查询哈希表的大小hsetnx,不存在则插入,存在则失败hincrby,哈希表中某个value + n,只适合处理数字类型的valuehincrbyfloat,哈希表中某个值增加,可以是小数
使用哈希存储的场景
- 当作结构体/对象使用,存储一个具有多个属性的对象,可以节省分开存的key的个数,适合存结构化的数据,而且只需要
改一个字段,不需要将整个字段读出来再写回去 - 与数据库相比,使用哈希存储具有稀疏性,不需要的字段就不存;但是对于数据库而言,在一个表中,即使某个对象不具有某个值也需要用null来占位
列表
- 列表类似于顺序表的使用,实现容器类似于deque,提升插入、删除的效率
- 列表是有序的,意思是元素相同,顺序不一样就是两个列表
lpush lpop rpush rpop
push_front pop_front push_back pop_back
lrem lindex lrange
lrem key count value,表示将key列表中的count个value(有多少删多少)删除并返回lrange key start stop,表示将key列表中[start, stop]的下标的内容返回(显示查询出结果的时候,前面带的数字不是下标,是结果集的序号),当下标超出的时候会取余调整lindex key index,表示获得key列表中下标为index的元素
lpushx 和 rpushx
- x代表exist,如果列表存在的话插入,否则插入失败
lpop 和 rpop
lpop keyname [count],从左端删除,后面的count在低版本的不支持rpop keyname [count],从右端删除- 与lpush和rpush搭配就可以当作栈、队列使用
linsert
linsert keyname [before|after] pivot value, pivot是从左到右寻找的一个值(如果没有找到就插入失败)
lrem
lrem keyname count element,count > 0时,从左到右移除count个元素;count == 0,移除列表中所有element相等的元素;count < 0时,从右向左移除count个元素
ltrim 和 lset
ltrim,ltrim keyname start stop截取[start, stop]的区间之后,剩下部分丢弃lset,lset keyname index element将index下标设置为element,其中index超过范围时,会报错
blpop 和 brpop
- 两者都是阻塞等待,但是在redis中,首先第一点,这两个阻塞是特殊的,并不会影响redis核心逻辑的工作,第二点就是这个阻塞队列并不会考虑队列满的情况,只会考虑队列为空的阻塞
blpop keyname timeout,0表示一直阻塞等待,以秒为单位等待- 两者可以同时等待多个队列,从左到右第一个有数据出队列时返回
list列表的应用场景
- 时间轴、消息轴等,通过lpush插入最新内容,通过lrange完成分页获取,通过ltrim完成部分内容的保留
- 消息队列,通过lpush + brpop就可以完成阻塞队列的搭建
set集合
set与列表相比,是无序的,意思是顺序不重要,同时set中不允许有相同元素,但是列表可以
sadd smember sismember scard
sadd key elements往set中添加元素smembers key,获取set中的所有元素sismember key member,判断一个value是否是key’s set中的元素scard keyname,获取集合中的元素个数
spop srandmember
spop keyname,从set中随机获取一个元素并且从set中删除srandmember keyname,从set中随机获取一个元素,但是并不会删除set中的返回元素
srem smove
srem keyname element,删除指定set中的指定元素smove source destination element,将source set中的element移动给element,如果移动destination中已经存在的元素也能移动成功,但是发生替换
sinter sinternstore 交集
sinter setname1 setname2 ...,求出两者的交集sinterstore destination setname1 setname2 ...,求出两者的交集,放到destination集合中
sunion sunionstore sdiff sdiffstore
分别取求并集和差集,使用方式与求交集相同
set的应用场景
- 用来存储用户画像,通过一个一个标签(其实就是小字符串)的形式存储在set当中
- 好友的推荐,因为set非常方便求交集,所以可以快速推荐共同好友等
- uv的统计(对于一个产品的评价,可以用两种方法来统计,一个是pv,另一个是uv;pv是page view,统计出用户每次访问服务器的次数,uv是userview,统计有多少用户访问了服务器,这意味着需要大量的去重操作,也是set擅长的)
zset
zset也是有序的,但是zset的有序是真正的有顺序的,通过在插入时基于score的结构实现。score和member一一对应,类似std::pair
zadd
zadd key [nx|xx] [gt|lt] [ch] [incr] score member [score member ...]
- 返回值的问题,zadd默认的返回值是新增元素的个数,但是如果设置了ch,就会返回修改元素的个数
- gt|lt,greater than | less than,前者是只有当前更新的score大于原来的score时才更新,后者反之
- nx|xx,nx表示只新增不修改,xx表示只修改不新增
- incr使用类似于incrby,不过作用对象是score
zrange
zrange key start end [withscore],展示zset中的全部元素,withscores表示展示相应元素分数zrevrange key start end [withscore],表示逆序展示(start, range)的memberzrangebyscore key start end [withscore],表示根据score从低到高排序展示member,前面两个start、end表示的是下标
zcount
zcount key start end,用来统计某个score区间中member的个数,如果要表示一个数字是开区间的一端的话就在前面加上(,例如(2, 5)表示为(2 (5- zcount支持使用正负无穷大作为最大值、最小值(-inf, inf);
zcard
zcard key,统计member个数
zpopmax
- zset在redis中默认排的是升序,zpopmax会删除score最大的member,并返回删除的member和score
zpopmax key [count]表示连续取count个最大member,时间复杂度o(logn * m);
bzpopmax
bzpopmax key \[key...\] timeout,阻塞的取最大member,超时时间为timeout(0为一直阻塞),可以等待多个key,当任意一个有返回时,阻塞结束,因此时间复杂度是o(logn);
zpopmin bzpopmin
两者使用和zpopmax、bapopmax相同,区别是操作的是zset中的最小值
zrank zrevrank zscore
zrank key member [withscore],查询member在有序列表中的下标,从前往后算,就和正常数组一样zrevrank key member withscore,查询member在有序数组中从后往前的下标,即最后一个元素下标为0zscore key member,查询member的分数,为了优化效率,redis牺牲空间,换取了该操作o(1)的时间复杂度
zrem zremrangebyrank zremrangebyscore
zrem key member,删除member成员,时间复杂度o(logn);zremrangebyrank key start end,删除下标[start, end]的成员,时间复杂度o(logn + m),因为只需要找到一个七点就可以往后删除zremrangebyscore key min max,删除分数[min, max]的成员,支持使用’('去指定开区间
zincrby
zincrby key increment member,给member的分数增加increment,increment可以是小数,也可以是负数,表示减小分数
zinterstore
zinterstore destination keynum key \[key...\] weights \[weight...\] \[aggregate sum | min | max\]
- destination表示存储交集的名称,keynum用于指定一共有多少个key制定了要求交集的zset(类似于http协议报头中的content-length),weights表示接下来的内容用于指定权重,可以是整数也可以是小数,其与共同的member的score相乘后得到结果作为新的score,而具体怎么作用有aggregate后的内容决定,默认是sum,新的score由所有的相加形成,min为所有的score的最小值,max为最大值
- 在最坏情况下,时间复杂度为
o(n*k) + o(m*log(m)),其中n为最小集合的元素个数,k为求交集的元素个数,m为最后交集中
元素的个数
zunionstore
zunionstore destination keynum key \[key...\] weights \[weight\] \[aggregate sum | min | max\]
- 求并集,使用方法与zinterstore类似
- 时间复杂度是
o(n) + o(m*log(m)),n是元素总个数,m是并集中元素的个数
zset的应用场景
- 排行榜系统,微博热搜、游戏天梯排行、成绩排行
- 加权的排行,可以维护多个zset,按照不同的权重使用zinterstore zunionstore等
其他类型
- stream,阻塞队列,用来让redis作为消息队列使用
- geospatial,用来存储坐标(经纬度),适合存储一些点之后,根据用户给定的坐标,按照半径或者矩阵区域等进行查找
- hyperloglog,用来估算集合中的元素个数,通过存储元素的特征而不是元素本身的方式,最多使用12kb的空间,就能够完成与真实数据浮动至多0.8%的差异的数据量统计,对于精准度要求不是那么高的uv pv统计就可以采用hyperloglog
- bitmap,实际上是优化过的set,既能够存储元素,有节省了一定空间(当然没有hyperloglog节省的多),但是只支持整形的存储
bitfield,位域,可以理解成是一个字节数组,和c语言中的位段类似,能够为几个比特位赋予特殊的含义并进行读取、存储、计算等操作,相对于hash string,目的仍然是省空间
渐进式遍历
- 不同于直接使用类似于
keys *的方式去查找整个redis中的键,渐进式遍历采取一次查找一小部分的方式来查找到需要的内容。这样每一次花费的时间都较少,能够避免redis服务器被阻塞 scan cursor [match match] [count count] [type type],表示从cursor光标开始,寻找count个元素。这里的cursor并不是下表的意思,而是redis服务器在每次渐进式遍历结束后返回的下次渐进式遍历的开始位置,输入0表示从头开始遍,返回的新位置是0表示此次遍历结束;match表示通配符匹配,使用规则和keys的一样;type表示检索出的结果的类型- scan不指明的话,默认count为10;同时检索在redis服务器不会保留任何结果,所以检索到一半不再进行是可以的;渐进式遍历不一定是可靠的,如果出现遍历过程中已经完成遍历的数据又发生修改的情况可能会无法从检索结果中反馈
redis数据库操作
- redis中也是有数据库的概念的,但是没有mysql中那么强;默认redis与16个数据库,不允许增加或删除,默认数据的操作都是在0号数据库中进行
- redis中切换库使用
select index,表示切换0~15号数据库;使用dbsize来查看当前数据库中key的个数;使用flushdb [async|sync]来选择同步或者异步清空数据库;使用flushall来清空所有数据库的所有内容
redis自定义客户端编写
resp协议
- redis客户端和服务器之间采取的是为redis定制的resp协议,基于tcp建立连接,采取一问一答的方式完成cs之间的信息交互
- 对于客户端,发送请求通过bulk string数组将命令写入请求;服务器返回结果时,根据请求命令的返回情况,返回不同内容
协议格式
+ok\r\n
simple string,以 + 开头
-err\r\n
error,以 - 开头
:1000\r\n
整形,以:开头
$5\r\nhello\r\n
bulkstring,以$开头,相比simple string可以传输二进制数据
*2\r\n$5\r\nhelloworld$5\r\nhello\r\n
array,以*开头
redis-plus-plus
声明redis连接对象
#include <sw/redis++/redis.h>
sw::redis::redis redis("tcp://127.0.0.1:6379");声明ip和redis服务器端口号
使用ping方法检查连通性
std::string ret = redis.ping(); std::cout << ret << std::endl;
string
get、set方法
sw::redis::redis redis("tcp://127.0.0.1:6379");
using namespace std::chrono_literals;
redis.set("key1", "val1", 0s, sw::redis::updatetype::no_exist); //0s表示不设置过期时间,没有提供只传递更新策略的set函数
auto ret = redis.get("key1");
if(ret) std::cout << ret.value() << std::endl;set方法基本使用通过传入sw::redis::stringview的key、val即可设置简单键值对,stringview使用类似于std::string,但是他是只读的而且效率更高;返回值的类型是sw::redis::optionalstring,其中optional表示无效值,没有采用std::string的原因是一方面如果直接采用对象的话,那么无法很好的表示nil,另一方面如果返回对象指针,还要设计内存指向空间是否有效的问题。sw::redis::optionstring在结果有效时,可以通过value()接口获取返回内容,同时失败的情况也可通过他隐式转换为bool来得知
set还有第三、四个参数,分别用来表示过期时间和更新策略。过期时间使用std::chrono::milliseconds,更新策略分为sw::redis::updatetype::exist、sw::redis::updatetype::not_exist sw::redis::updatetype::always,分对应setnx setxx 和直接set
exists和del
sw::redis::redis redis("tcp://127.0.0.1:6379");
auto ret = redis.exists("key1");
ret = redis.del({"key1", "key2"});exists判断一个key是否存在,存在返回1,失败返回0del删除key,返回删除key的数目
keys
sw::redis::redis redis("tcp://127.0.0.1:6379");
vector<string> ret; auto it = std::back_inserter(ret);
redis.keys("*", it);keys用来获取所有的key,通过第一个参数的匹配规则来检索,方法和前面命令行中介绍的五种一样;同时为了解耦合,第二个参数要求传入输出型数据结构的尾插迭代器
expire和ttl
sw::redis::redis redis("tcp://127.0.0.1:6379");
using namespace std::chrono_literals;
bool ret = redis.expire("key", 10s); std::this_thread::sleep_for(5s);
long long len = redis.ttl("key");expire用来设置过期时间,通过std::chrono给定ttl用来判断剩余生存时间,以秒为单位。已经过期的key,返回值为-1;不存在的key,返回值为-2
type
sw::redis::redis redis("tcp://127.0.0.1:6379");
redis.set("key", "val");
std::string ret = redis.type("key");mget mset
sw::redis::redis redis("tcp://127.0.0.1:6379");
redis.mset({std::make_pair("key1", "val1"), std::make_pair("key2", "val2")});
std::vector<std::string> keys;
redis.mset(keys.begin(), keys.end());
std::vector<sw::redis::optionalstring> vals; auto bit = std::back_inserter(vals);
redis.mget({"key1", "key2"}, bit);
std::vector<std::string> vals2 = {"key1", "key2"};
redis.mget(vals2.begin(), vals2.end(), bit);mget方法支持通过初始化列表出入多个pair来表示要插入的多个键值对,或者可以采用迭代器的方式使用string数组的起止迭代器传参mset方法支持通过初始化列表或者sw::redis::optionalstring数组来传入多个key,也需要在最后传入一个尾插迭代器来带出结果
getrange setrange
sw::redis::redis redis("tcp://127.0.0.1:6379");
std::string ret = redis.getrange("key", 5, 10);
long long val = redis.setrange("key", 5, "ins_val");getrange返回[start, end]范围中的内容,返回的时普通的std::stringsetrange将从offset开始的内容,设置为给定的字符串,并返回完成更改后新的字符串的长度
incr decr
sw::redis::redis redis("tcp://127.0.0.1:6379");
long long ret1 = redis.incr("key");
long long ret2 = redis.decr("key");incr和decr返回更改过后的值,两者都是以一为单位;相比get方法,后者返回的是sw::redis::optionalstring,如果想要当作数字使用的话还要转换
list
- lpush lrange rpush rpop lpop
sw::redis::redis server("tcp://127.0.0.1:6379");
server.lpush("list1", "1");
server.lpush("list1", {"1", "2", "3"});
std::vector<std::string> vals = "1", "2", "3";
server.lpush("list1", vals.begin(), vals.end());
std::vector<std::string> rets;
auto bit = std::back_inserter(rets);
server.lrange("list1", bit);
auto ret1 = server.rpop("list1"); auto ret2 = server.lpop();lpush和rpush都是通过先指定列表名称,再指定元素的方式使用的。指定元素有三种方式:1. 直接给予,这样可以给一个;2. 通过初始化列表给予多个值;3. 现在外部容器构造完成,然后给予起止迭代器lrange,需要给予一个尾插迭代器,来带出遍历结果rpop和lpop,两个都是通过直接给予列表名称,然后返回sw::redis::optionalstring的方式获取两端元素
- brpop blpop
sw::redis::redis server("tcp://127.0.0.1:6379");
auto ret = server.blpop("list1", std::chrono::seconds(1));
if(ret)
{
std::cout << ret.value().first << ret.value().second << std::endl;
}- 两者都是阻塞式的获取列表收尾的元素。对于传参,可以直接给字符串,也可以通过初始化列表,也可以通过迭代器的方式;返回结果采用的是
optionalstring+pair的方式返回,因为可以等待多个队列,所以既返回列表名,也返回删除元素;也可以设置超时时间,超过仍未获取元素就直接返回
- llen
sw::redis::redis server("tcp://127.0.0.1:6379");
long long server.llen("list");llen用来获取列表长度
set
- sadd smembers
sw::redis::redis server("tcp://127.0.0.1:6379");
server.sadd("set", "1");
set<string> mems; auto in = std::inserter(mems, mems.end());
server.smembers("set", in);- redis-plus-plus的接口风格统一性是很高的。
sadd前面提到的三种方式都可以,smembers也是通过迭代器的方式将遍历结果带出
- sismember spop scard
sw::redis::redis server("tcp://127.0.0.1:6379");
bool exists = server.ismember("set", "1");
auto ret = spop("set"); if(ret) std::cout << ret.value() << std::endl;
long long num = scard("set");sismember,用来判断某个成员是否属于某个集合spop,用来随机返回集合中的一个元素scard,用来返回某个集合中的元素个数
hash
- hget hset
sw::redis::redis server("tcp://127.0.0.1:6379");
long long ret = server.hset("hash1", "1", "zhangsan");
ret = server.hset("hash1", {std::make_pair("2", "lisi"), std::make_pair("3", "wangwu")});
auto val = server.hget("hash1", "1"); if(val) std::cout << val.value() << std::endl;hset用来向哈希表中添加元素,依然可以通过直接给予、初始化列表、迭代器三种方式给予field-valuehget用获取哈希表中field-value中的value
- hexists hdel hlen
sw::redis::redis server("tcp://127.0.0.1:6379");
bool exists = server.hexists("hash1", "1");
long long ret = server.hdel("hash1", {"1", "2"});
ret = server.hlen("hash1");hexists用来判断某个field是否存在hdel用来删除多个field,并返回删除的个数hel,返回一个哈希表中field的个数
- hmset hmget hkeys hvals
std::vector<std::string> keys;
auto it = std::back_inserter(keys);
server.hkeys("hash1", it);
std::vector<std::string> vals;
it = std::back_inserter(vals);
server.hvals("hash1", it);
server.hmget("hash1", {"3", "4", "5"}, it);hmsethmget用来获取、设置多个元素,hkeyshvals用来获取一个哈希表中所有的fieldvalue
zset
- zadd zrange
server.zadd("zset1", "zhangsan", 1);
server.zadd("zset1", {std::make_pair("lisi", 2), std::make_pair("wangwu", 3)});
std::vector<std::pair<std::string, std::string>> pairs = {
std::make_pair("zhouliu", "4"),
std::make_pair("tianqi", "5")
};
server.zadd("zset1", pairs.begin(), pairs.end());
std::vector<std::string> withnoscore;
auto it = std::back_inserter(withnoscore);
std::vector<std::pair<std::string, double>> withscore; //通过模板类型来指定是否需要带出分数
auto it2 = std::back_inserter(withscore);
server.zrange("zset1", 0, -1, it2);zadd,往有序列表中加入成员和分数,依然支持前面的三种方法zrange,遍历获取有序列表中的元素,通过不同的输出容器来间接指定是否需要获取分数
- zcard zscore zrank zrem
long long ret = server.zcard("zset1");
auto score = server.zscore("zset1", "tianqi");
auto rank = server.zrank("zset1", "zhangsan");
server.zrem("zset1", "lisi");zcard,获取有序集合中成员的个数zscore,根据成员获取分数zrank,根据成员获取排名(在整个有序列表中的数组下标)zrem,删除某个有序列表中的成员
到此这篇关于详解redis终端操作和redis-plus-plus接口使用教程的文章就介绍到这了,更多相关redis终端和redis-plus-plus接口内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论