redis-plus-plus常用函数介绍以及redis的一些边缘知识

文章目录

    • 渐进式遍历
    • scan
    • 数据库管理
    • 使用C++调用redis
      • 安装redis-plus-plus
    • get, set, exists , del, keys
    • expire, type
    • string的set, mset, mget
    • getrange, setrange
    • incr, decr
    • lpush, lrange,
    • lpop, rpop
    • blpop, llen
    • sadd, smembers
    • sismember, scard
    • sinter, sinterstore
    • hset, hget, hexists, hdel, hmget
    • zadd, zrange
    • zrem, zsocre, zrank

渐进式遍历

keys能够通过通配符匹配规则,将redis中所有符合条件的key筛选出来

keys pattern

但是这个命令很危险,若redis中的数据很多,导致keys的执行时间过长。由于redis是单线程,所以keys大概率将引起阻塞

通过渐进式遍历,就可以做到在保证服务器不阻塞的情况下,获取所有的key
渐进式遍历不是一次新地将所有key拿到,而是每执行一次命令,只获取其中一部分的key。这样就保证了每次操作不会阻塞服务器,要想获取所有的key,需要多次执行渐进式遍历

渐进式遍历其实是一组命令,这些命令的使用方法是一样的,其中的代表命令为scan

scan

scan cursor [pattern] [COUNT count] [TYPE type]

cursor:光标,执行当前遍历的位置,为0表示从头开始遍历。不能将其理解为下标,它只是一个字符串
count:限制这次的遍历要获取的元素数量,默认是10。和MySQL的limit不一样,count只是一个建议,返回结果的数量并不一定和count相同,只是和count差不多
type:根据key对应的value类型进行进一步的筛选
返回值分两部分:一部分为提示,下一次遍历时光标要从哪开始
一部分为遍历到的具体内容

当前已有的key
image.png

输入scan 0
image.png
7为下次遍历时,需要指定的光标位置,剩下的数据为遍历到的元素

当scan返回空集合或者光标为0,说明遍历结束
image.png
指定count参数为5,返回了6个结果
image.png

scan可以随时终止,不会对服务器产生任何副作用
若执行scan的过程中,key发生了变化(增加,删除),那么scan可能会出现遗漏或重复

数据库管理

MySQL中,可以创建多个数据库database。而在redis中,只能使用现成的(已经存在的)数据库,无法删除/创建数据库。redis提供了16个数据库(0~15),并且默认使用的是0号数据库
通过

select index

index为0~15,选择数据库
实际使用中很少切换数据库,一般都是直接使用0号数据库

获取当前数据库下的key数量:

dbsize

删除当前数据库中的所有key

flushdb

删除所有数据库中的所有key

flushall

使用C++调用redis

redis自定义了一个通信协议:RESP(redis serialization protocol)
要实现一个自定义客户端,就必须清楚服务端使用的协议。由于redis将协议的内容公开,所以我们能实现自己的redis客户端

RESP协议
优点:

  1. 简单好实现
  2. 快速进行解析
  3. 可读性高
    传输层基于TCP,但是与TCP没有强耦合关系
    请求和相应之间的通信模型是一问一答的
    客户端以bulk string数组的形式将命令发送给服务器,不同的命令返回结果不一样

服务端返回的数据:

  • 对于简单字符串(Simple String),第一个字节为"+"
  • 对于错误(Errors),第一个字节为"-"
  • 对于整数(Integers),第一个字节为":"
  • 对于Bulk String,第一个字节为"$"
  • 对于数组(Arrays),第一个字节为"*"

Bulk String和Simple String的区别,Bulk String可以用于传输二进制数据,因为其实现了二进制安全,而Simple String只能用于传输简单字符串

这些协议的序列化与反序列化已经有第三方库实现,我们不需要手动实现

安装redis-plus-plus

安装hiredis:

apt install -y libhiredis-dev

通过源码编译安装redis-plus-plus
下载源码:

git clone https://github.com/sewenew/redis-plus-plus.git

进入目录:

cd redis-plus-plus/

创建目录并进入:

mkdir build
cd build

安装cmake:

apt install -y cmake

执行:

cmake ..

最后安装:

make         # 编译生成动静态库
make install # 将动静态库拷贝到系统目录中

安装完成后,在/usr/local/include目录下会出现sw目录,存储了redis的头文件
/usr/local/lib目录下也存储了redis的库文件

ls /usr/local/include/sw
ls /usr/local/lib | grep redis

image.png
使用find命令查找相关文件也可以

find / -name "redis*"
find / -name "libredis*"

编写demo连接redis服务器,使用ping命令检测连通性

#include <iostream>
#include <string>
#include <sw/redis++/redis++.h> // 包含redis头文件
using std::cout;
using std::cin;
using std::endl;int main()
{// 创建Redis对象时,需要指定redis服务的IP和端口// 字符串为一个url,RESP协议是基于TCP应用层协议sw::redis::Redis redis("tcp://127.0.0.1:6379"); std::string res = redis.ping();cout << res << "\n";return 0;
}

要想与redis进行交互,就要初始化一个sw::redis::Redis对象,在redis命令行中输入的命令都能通过sw::redis::Redis进行发送。其中sw::redis是一个命名空间,其中定义了很多redis相关的类和方法
需要将一个url作为构造函数的参数传入,比如:“tcp://127.0.0.1:6379”,这个url中,tcp表示用tcp协议进行通信(redis是基于tcp的),127.0.0.1表示redis服务所在的IP地址,6379表示redis服务所在的端口号
redis.ping()等价于在redis命令行中输入ping,由于这个命令返回一个字符串,用string将其接收并打印

编写makefile文件,需要将使用到的动态库放到编译指令中(hiredis, redis++, pthread)

demo:demo.ccg++ -o $@ $^ -std=c++17 -lpthread -lhiredis -lredis++.PHONY:clean
clean:rm -rf demo

配置系统文件,使链接器能找到hiredis的动态库,其他动态库已经位于系统路径下

cd /etc/ld.so.conf.d

创建配置文件,将find / -name libhiredis*返回的目录写入配置文件中
image.png
写入动态库所在目录即可

vim redis.conf

image.png
执行

sudo ldconcig

此时配置完成
执行demo返回PONG说明redis-plus-plus安装完成
image.png

get, set, exists , del, keys

set:

void set(const sw::redis::StringView &key, const sw::redis::StringView &val);

其中StringView是sw::redis中定义的一个只读字符串(相比于普通字符串,StringView做了更多的优化),以字符串的形式传入key和value的值即可,如redis.set("k1", "111");

get:

sw::redis::OptionalString get(const sw::redis::StringView &key)

将key以字符串的形式传入,get将返回key对应的value值。返回值为sw::redis::OptionalString,该类重载了bool,若key不存在,那么OptionalString的bool值为false。若key存在,那么OptionalString的bool值为true
由于该类没有重载<<运算符,所以不能直接输出,但该类的value()方法可以以字符串的方式返回value值,value()的返回值可以直接输出

// get set的使用
void test1(sw::redis::Redis& redis)
{redis.flushall(); // 清空当前数据库,慎用redis.set("k1", "111");redis.set("k2", "222");redis.set("k3", "333");auto v1 = redis.get("k1");if (v1) cout << "k1-" << v1.value() << "\n";auto v2 = redis.get("k2");if (v2) cout << "k2-" << v2.value() << "\n";auto v3 = redis.get("k3");if (v3) cout << "k3-" << v3.value() << "\n";auto v4 = redis.get("k4");if (v4) cout << "k4-" << v4.value() << "\n";
}

image.png

exists:

long long exists(const sw::redis::StringView &key);

以字符串的方式传入key,exists将返回存在的key的数量
用初始化列表存储多个字符串,并将初始化列表作为参数传入,就能询问这些key是否在数据库中存在

void test2(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "111");redis.set("k2", "222");redis.set("k3", "333");auto t = redis.exists("k1");cout << "k1:" << t << "\n";t = redis.exists({"k1", "k2", "k3"});cout << "k1, k2, k3:" << t << "\n";t = redis.exists("t4");cout << "k4:" << t << "\n";
}

image.png

del和exists的使用相同,参数一样,也能使用初始化列表作为参数删除多个key,返回值为成功删除的元素数量

void test3(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "111");redis.set("k2", "222");redis.set("k3", "333");auto t = redis.exists({"k1", "k2", "k3"});cout << "k1, k2, k3:" << t << "\n";redis.del("k2");t = redis.del({"k1", "k2", "k3"});cout << "del->k1, k2, k3:" << t << "\n";t = redis.exists({"k1", "k2", "k3"});cout << "k1, k2, k3:" << t << "\n";
}

image.png

keys:

void Redis::keys(const StringView &pattern, Output output)

key的第一个参数为字符串形式的规则表达式,用来匹配key
keys的第二个参数为一个插入迭代器,我们需要先创建一个存储结果的容器,再创建一个指向该容器的插入迭代器,将其作为keys的第二个参数,keys的返回结果将保存到之前创建的容器中
STL中有五种迭代器:

  1. 输入迭代器(只读)
  2. 输出迭代器(可写)
  3. 前向迭代器
  4. 双向迭代器
  5. 随机访问迭代器

插入迭代器属于一种输出迭代器(用来将数据输出),有三种插入迭代器

  1. front_insert_iterator(将数据输出到容器的开头)
  2. back_insert_iterator(将数据输出到容器的末尾)
  3. insert_iterator(将数据输出到容器的任意位置,指向位置之前)

每种迭代器都有相应的方法,调用这些方法以构造相应的迭代器
如back_inserter(),将容器作为参数传入,该方法返回相应的迭代器
使用:

vector<string> res;
auto it = std::back_inserter(res);
template <class T>
void printContainer(const T& container)
{for (const auto& elem : container){cout << elem << "\n";}
}void test4(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "111");redis.set("k2", "222");redis.set("k3", "333");redis.set("k4", "444");redis.set("k5", "555");redis.set("k6", "666");vector<string> res;auto it = std::back_inserter(res);redis.keys("*", it);printContainer(res);
}

image.png

expire, type

expire

bool Redis::expire(const StringView &key, const std::chrono::seconds &timeout)

以字符串的形式将key作为第一个参数,将时间作为第二个参数

#include <chrono>
using namespace std::chrono_literals;

引入头文件和声明命名空间:C++11之后,支持了更多的字面值,如3s,7min,以及h, ms, us, ns。这些字面值可以提高程序的可读性
expire的第二个参数就可以使用7s这样的字面值,前提是引入头文件和声明命名空间

ttl:

long long sw::redis::Redis::ttl(const sw::redis::StringView &key)

ttl返回long long表示key的剩余存活时间

void test5(sw::redis::Redis& redis)
{using namespace std::chrono_literals;redis.flushall();redis.set("k1", "111");redis.expire("k1", 7s);std::this_thread::sleep_for(3s); // 线程休眠3sauto time = redis.ttl("k1");cout << "k1:" << time << "s" << "\n";
}

image.png

type:

std::string sw::redis::Redis::type(const sw::redis::StringView &key)

返回key所属的类型,返回值是类型是std::string

void test6(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "111");redis.lpush("k2", "222");auto res = redis.type("k1");cout << "k1:" << res << "\n";res = redis.type("k2");cout << "k2:" << res << "\n";
}

image.png

string的set, mset, mget

超时设置与NX|XX

redis.set("k1", "111", 5s, sw::redis::UpdateType::EXIST)

第三个参数为超时时间,引入了chrono头文件并使用命名空间std::chrono_literals后,即可使用这样的字面值
第四个参数有两个可选项:sw::redis::UpdateType::NOT_EXIST和sw::redis::UpdateType::EXIST。分别对应着NX和XX模式,即只创建与只更新两种模式

若不想使用第三个参数,但是要使用第四个参数,将第三个参数设置为0s即可

mset:

// 第一种方法
redis.mset({std::make_pair("k1", "111"), std::make_pair("k2", "222")});// 第二种方法
vector<std::pair<string, string>> keys = {{"k1", "111"},{"k2", "222"},{"k3", "333"}
};
redis.mset(keys.begin(), keys.end());

第一种方法:直接用初始化列表存储多个pair,将初始化列表作为参数传入
第二种方法:将多个键值对保存到容器中,将容器的头尾迭代器传入

mget的使用和keys类似,需要先创建一个保存结果的容器,再创建一个指向该容器的插入迭代器并将该容器传入
至于说mget的第一个参数,用初始化列表存储要查询的key即可,具体见demo

void test1(sw::redis::Redis& redis)
{redis.flushall();// mset的第一种使用方法redis.mset({std::make_pair("k1", "111"), std::make_pair("k2", "222")});// mset的第二种使用方法vector<std::pair<string, string>> keys = {{"k1", "111"},{"k2", "222"},{"k3", "333"}};redis.mset(keys.begin(), keys.end());vector<sw::redis::OptionalString> res;auto it = std::back_inserter(res); redis.mget({"k1", "k2", "k3"}, it);printContainerOptional(res);
}

image.png

getrange, setrange

getrange

std::string sw::redis::Redis::getrange(const sw::redis::StringView &key, long long start, long long end)

传入key与一个闭区间的左右端点,getrange将返回key对应value的子字符串。若区间方法,将返回空字符串

void test2(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "helloworld");string res = redis.getrange("k1", 3, 7);cout << "helloworld(3, 7):" << res << "\n";
}

image.png

setrange

long long setrange(const sw::redis::StringView &key, long long offset, const sw::redis::StringView &val)

将key对应的value,从offset个字符开始往后替换为val字符串

void test2(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "helloworld");string res = redis.getrange("k1", 3, 7);cout << "helloworld(3, 7):" << res << "\n";redis.setrange("k1", 3, "xxxxx");auto val = redis.get("k1");cout << val.value() << "\n";
}

image.png

incr, decr

long long sw::redis::Redis::incr(const sw::redis::StringView &key)

将传入的key对应的value值自增1,并且返回自增后的结果,类型为long long
如果用get获取其value,那么其类型为OptionalString,需要调用其value方法并将字符串转换成整数才能使用
所以要使用incr的结果,推荐接收incr的返回值

void test3(sw::redis::Redis& redis)
{redis.flushall();redis.set("k1", "2");auto res = redis.incr("k1");cout << res << "\n";res = redis.decr("k1");cout << res << "\n";
}

image.png

lpush, lrange,

lpush:指定要插入的key,可以插入一个/多个key
插入多个key时,可以通过初始化列表也可以通过迭代器的方式进行

long long lpush(const sw::redis::StringView &key, const sw::redis::StringView &val)
long long lpush<T>(const sw::redis::StringView &key, std::initializer_list<T> il)
long long lpush<Input>(const sw::redis::StringView &key, Input first, Input last)

lrange:

void lrange<Output>(const sw::redis::StringView &key, long long start, long long stop, Output output)

lrange获取list中指定范围内的元素,参数和命令行相同,只是需要添加一个插入迭代器以保存多个元素

void test1(sw::redis::Redis& redis)
{redis.flushall();redis.lpush("k1", "111");redis.lpush("k1", "222");vector<string> data = {"333", "444", "555"};redis.lpush("k1", data.begin(), data.end());vector<string> res;auto it = back_inserter(res);redis.lrange("k1", 0, -1, it);printContainer(res);
}

image.png

lpop, rpop

lpop:
将key对应list的头部元素删除并返回,返回类型为OptionalString,需要判断其bool值是否为真,再调用其value方法,输出被删除的值

sw::redis::OptionalString lpop(const sw::redis::StringView &key)
void test1(sw::redis::Redis& redis)
{redis.flushall();redis.lpush("k1", "111");redis.lpush("k1", "222");vector<string> data = {"333", "444", "555"};redis.lpush("k1", data.begin(), data.end());vector<string> res;auto it = back_inserter(res);redis.lrange("k1", 0, -1, it);printContainer(res);auto t = redis.lpop("k1");if (t) cout << "pop:" << t.value() << "\n";
}

image.png

blpop, llen

阻塞版本的头删除,可以用第二个参数设置阻塞时间,默认为0秒
第一个参数可以是一个key,也可以是多个key(初始化列表或者迭代器),但是只会删除第一个有数据key

sw::redis::OptionalStringPair blpop(const sw::redis::StringView &key, const std::chrono::seconds &timeout = std::chrono::seconds{0})

返回类型为OptionalStringPair,可以理解为pair<string, string>,第一个元素为被删除元素所属key,第二个元素为被删除元素
假设有一个OptionalStringPair对象v,获取第一个参数v.value().first,或者v->first,该类重载了->运算符,可以通过->直接获取参数值

void test1(sw::redis::Redis& redis)
{redis.flushall();redis.lpush("k1", "111");redis.lpush("k1", "222");vector<string> data = {"333", "444", "555"};redis.lpush("k1", data.begin(), data.end());vector<string> res;auto it = back_inserter(res);redis.lrange("k1", 0, -1, it);printContainer(res);auto t = redis.lpop("k1");if (t) cout << "pop:" << t.value() << "\n";auto v = redis.blpop("k1", 10s);if (v) cout << "key:" << v->first << " val:" << v.value().second << "\n";
}

image.png

llen:返回指定key的长度,类型为long long

long long llen(const sw::redis::StringView &key)
void test1(sw::redis::Redis& redis)
{redis.flushall();redis.lpush("k1", "111");redis.lpush("k1", "222");vector<string> data = {"333", "444", "555"};redis.lpush("k1", data.begin(), data.end());vector<string> res;auto it = back_inserter(res);redis.lrange("k1", 0, -1, it);printContainer(res);auto t = redis.lpop("k1");if (t) cout << "pop:" << t.value() << "\n";auto v = redis.blpop("k1", 10s);if (v) cout << "key:" << v->first << " val:" << v.value().second << "\n";cout << "len:" << redis.llen("k1") << "\n";
}

image.png

sadd, smembers

sadd同样支持一次插入一个/多个元素,方法与之前的函数类型,这里不再赘述
smembers:

void smembers<Output>(const sw::redis::StringView &key, Output output)

指定要获取的key,该函数将value值保存到插入迭代器指向的容器中,和之前的获取函数的使用类似

void test2(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});std::set<string> res;auto it = inserter(res, res.begin());redis.smembers("k1", it);printContainer(res);
}

image.png

sismember, scard

sismember:

bool sismember(const sw::redis::StringView &key, const sw::redis::StringView &member)

函数返回一个bool,表示member是否为key的元素

void test2(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});std::set<string> res;auto it = inserter(res, res.begin());redis.smembers("k1", it);printContainer(res);cout << "111 is k1 member? :" << redis.sismember("k1", "111") << "\n";
}

image.png

scard:获取set中的元素个数

long long scard(const sw::redis::StringView &key)
void test2(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});std::set<string> res;auto it = inserter(res, res.begin());redis.smembers("k1", it);printContainer(res);cout << "111 is k1 member? :" << redis.sismember("k1", "111") << "\n";cout << "scard:" << redis.scard("k1") << "\n";
}

image.png

spop:

sw::redis::OptionalString spop(const sw::redis::StringView &key)
void test2(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});std::set<string> res;auto it = inserter(res, res.begin());redis.smembers("k1", it);printContainer(res);cout << "111 is k1 member? :" << redis.sismember("k1", "111") << "\n";cout << "scard:" << redis.scard("k1") << "\n";auto t = redis.spop("k1");if (t) cout << "spop:" << t.value() << "\n";
}

image.png

sinter, sinterstore

sinter:

void sinter<T, Output>(std::initializer_list<T> il, Output output)

初始化列表表示用求并集的key,output为保存并集的插入迭代器

void test3(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});redis.sadd("k2", {"222", "333", "444"});std::set<string> res;auto it = inserter(res, res.begin());redis.sinter({"k1", "k2"}, it);printContainer(res);
}

image.png

sinterstore:

long long sinterstore<T>(const sw::redis::StringView &destination, std::initializer_list<T> il)

第一个参数为存储并集的key,第二个参数为求哪些集合并集

void test3(sw::redis::Redis& redis)
{redis.flushall();redis.sadd("k1", {"111", "222", "333"});redis.sadd("k2", {"222", "333", "444"});std::set<string> res;auto it = inserter(res, res.begin());redis.sinter({"k1", "k2"}, it);printContainer(res);redis.sinterstore("k3", {"k1", "k2"});std::set<string> t;it = inserter(t, t.begin());redis.smembers("k3", it);printContainer(t);
}

image.png

hset, hget, hexists, hdel, hmget

hset:

long long hset(const sw::redis::StringView &key, const sw::redis::StringView &field, const sw::redis::StringView &val)
long long hset(const sw::redis::StringView &key, const std::pair<sw::redis::StringView, sw::redis::StringView> &item)
long long hset<T>(const sw::redis::StringView &key, std::initializer_list<T> il)
long long hset<Input>(const sw::redis::StringView &key, Input first, Input last)

支持一次插入一个/多个元素,由于hash存储的是field和value,所以初始化列表中的元素需要为pair,容器中的元素也需要为pair

hget:获取key的field对应的value

sw::redis::OptionalString hget(const sw::redis::StringView &key, const sw::redis::StringView &field)
void test4(sw::redis::Redis& redis)
{redis.flushall();redis.hset("k1", {std::make_pair("kk1", "111"), std::make_pair("kk2", "222")});auto res = redis.hget("k1", "kk1");if (res) cout << res.value() << "\n";
}

image.png

hexists:判断key的field是否存在

bool hexists(const sw::redis::StringView &key, const sw::redis::StringView &field)
void test4(sw::redis::Redis& redis)
{redis.flushall();redis.hset("k1", {std::make_pair("kk1", "111"), std::make_pair("kk2", "222")});auto res = redis.hget("k1", "kk1");if (res) cout << res.value() << "\n";cout << "k1的kk2是否存在? :" << redis.hexists("k1", "kk2") << "\n";
}

image.png

hdel:

long long hdel(const sw::redis::StringView &key, const sw::redis::StringView &field)
long long hdel<T>(const sw::redis::StringView &key, std::initializer_list<T> il)
long long hdel<Input>(const sw::redis::StringView &key, Input first, Input last)

支持一次删除一个/多个key的field,返回值为成功删除的field数量

hkeys:获取key下的fields

void hkeys<Output>(const sw::redis::StringView &key, Output output)

hvals:获取key下的values

void hvals<Output>(const sw::redis::StringView &key, Output output)
void test5(sw::redis::Redis& redis)
{redis.flushall();redis.hset("k1", {std::make_pair("kk1", "111"), std::make_pair("kk2", "222"),std::make_pair("kk3", "333"),std::make_pair("kk4", "444"),});vector<string> keyres;auto it = back_inserter(keyres);redis.hkeys("k1", it);cout << "keys:\n";printContainer(keyres);vector<string> valres;it = back_inserter(valres);redis.hvals("k1", it);cout << "vals:\n";printContainer(valres);
}

image.png

hget只支持获取单个key下field对应的value
而hmget支持获取一个/多个key下field对应的value

void hmget<T, Output>(const sw::redis::StringView &key, std::initializer_list<T> il, Output output)
void hmget<Input, Output>(const sw::redis::StringView &key, Input first, Input last, Output output)
void test6(sw::redis::Redis& redis)
{redis.flushall();redis.hset("k1", {std::make_pair("kk1", "111"), std::make_pair("kk2", "222"),std::make_pair("kk3", "333"),std::make_pair("kk4", "444"),});vector<string> res;auto it = back_inserter(res);redis.hmget("k1", {"kk1", "kk2"}, it);printContainer(res);
}

image.png

zadd, zrange

zadd

long long zadd(const sw::redis::StringView &key, const sw::redis::StringView &member, double score)
long long zadd<T>(const sw::redis::StringView &key, std::initializer_list<T> il)
long long zadd<Input>(const sw::redis::StringView &key, Input first, Input last)

zadd支持一次向有序集合中添加一个/多个元素,添加多个元素时,元素的类型为pair<string, double>

zrange:
根据指定范围查询,可以只查询member,也可以查询member和score

void zrange<Output>(const sw::redis::StringView &key, long long start, long long stop, Output output)

若插入迭代器指向的容器类型为<string, double>,那么此时查询member和score
若插入迭代器指向的容器类型为string,那么此时查询member

void test7(sw::redis::Redis& redis)
{redis.flushall();redis.zadd("k1", {std::make_pair("aa", "99"),std::make_pair("bb", "98"),std::make_pair("cc", "97")});vector<std::pair<string, double>> resms;auto itms = back_inserter(resms);vector<string> resm;auto itm = back_inserter(resm);redis.zrange("k1", 0, -1, itms);redis.zrange("k1", 0, -1, itm);cout << "只查询member:\n";for (auto t : resm) cout << t << "\n";cout << "查询member和score:\n";for (auto t : resms) cout << t.first << ' ' << t.second << "\n";
}

image.png

zrem, zsocre, zrank

zrem

long long zrem(const sw::redis::StringView &key, const sw::redis::StringView &member)
long long zrem<T>(const sw::redis::StringView &key, std::initializer_list<T> il)
long long zrem<Input>(const sw::redis::StringView &key, Input first, Input last)

支持一次删除key下的一个/多个member,返回成功删除的数量

zscore:返回key下member对应的score

sw::redis::OptionalDouble zscore(const sw::redis::StringView &key, const sw::redis::StringView &member)
sw::redis::OptionalLongLong zrank(const sw::redis::StringView &key, const sw::redis::StringView &member)
void test8(sw::redis::Redis& redis)
{redis.flushall();redis.zadd("k1", {std::make_pair("aa", "99"),std::make_pair("bb", "98"),std::make_pair("cc", "97")});auto res = redis.zscore("k1", "bb");if (res) cout << "zscore(k1.bb):" << res.value() << "\n";auto t = redis.zrank("k1", "bb");if (t) cout << "zrank(k1.bb)" << t.value() << "\n";
}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/158220.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MVCC详解

什么是MVCC&#xff1f; MVCC&#xff0c;即Multi-Version Concurrency Control &#xff08;多版本并发控制&#xff09;。它是一种并发控制的方法&#xff0c;一般在数据库管理系统中&#xff0c;实现对数据库的并发访问&#xff0c;在编程语言中实现事务内存。 通俗的讲&am…

Azure 机器学习 - 使用 AutoML 和 Python 训练物体检测模型

目录 一、Azure环境准备二、计算目标设置三、试验设置四、直观呈现输入数据五、上传数据并创建 MLTable六、配置物体检测试验适用于图像任务的自动超参数扫描 (AutoMode)适用于图像任务的手动超参数扫描作业限制 七、注册和部署模型获取最佳试用版注册模型配置联机终结点创建终…

框架安全-CVE 复现Apache ShiroApache Solr漏洞复现

文章目录 服务攻防-框架安全&CVE 复现&Apache Shiro&Apache Solr漏洞复现中间件列表常见开发框架Apache Shiro-组件框架安全暴露的安全问题漏洞复现Apache Shiro认证绕过漏洞&#xff08;CVE-2020-1957&#xff09;CVE-2020-11989验证绕过漏洞CVE_2016_4437 Shiro-…

【微服务 Spring Cloud Alibaba】- Nacos 服务注册中心

目录 1. 什么是注册中心&#xff1f; 1.2 注册中心的作用 2. SpringBoot 整合 Nacos 实现服务注册中心 2.1 将服务注册到 Nacos 2.2 实现消费者 3. 服务列表各个参数的含义、作用以及应用场景 1. 什么是注册中心&#xff1f; 注册中心是微服务架构中的一个重要组件&…

算法---缺失的第一个正数

题目 给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。示例 1&#xff1a;输入&#xff1a;nums [1,2,0] 输出&#xff1a;3 示例 2&#xff1a;输入&#xff1a;nums …

分享一下怎么做小程序营销活动

小程序营销活动已经成为现代营销的必备利器&#xff0c;它能够帮助企业提高品牌知名度、促进产品销售&#xff0c;以及加强与用户的互动。然而&#xff0c;要想成功地策划和执行一个小程序营销活动&#xff0c;需要精心设计和全面规划。本文将为您介绍小程序营销活动的策划和执…

计算机的输入输出设备

文章目录 前言一、常见的输入输出设备1.字符输入设备2.图形输入设备3.图像输出设备 二、输入输出接口的通用设计三、CPU与IO设备的通信1.程序中断2.DMA&#xff08;直接存储器访问&#xff09; 前言 今天给大家介绍计算机的输入输出设备&#xff0c;包括三个板块&#xff1a;常…

基于QT的简易计算器(一)

目录 0 简介1.设计原理1.1界面设计1.1.1界面基本布局1.1.2 界面调整和美化1.1.2 控件重命名 1.2 连接信号和槽1.3 软件逻辑1.3.1四则运算1.3.2 连续运算&#xff08;不完全&#xff09;的原理1.3.3 清屏1.3.4 退格1.3.5 等于1.3.6 小数点 2.总结与拓展 0 简介 最近在学QT&…

初识FFmpeg

前言 无意间见到群里的小伙伴展示视频工具。功能比较多&#xff0c;包括视频编码修改&#xff0c;画质处理&#xff0c;比例处理、名称提取&#xff0c;剪辑、标题拆解。因此开始了FFmpeg学习。以下摘自百度百科的解释。 FFmpeg是一套可以用来记录、转换数字音频、视频&#xf…

BUUCTF ningen 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 人类的科学日益发展&#xff0c;对自然的研究依然无法满足&#xff0c;传闻日本科学家秋明重组了基因序列&#xff0c;造出了名为ningen的超自然生物。某天特工小明偶然截获了日本与俄罗斯的秘密通信&#xff0c;文…

Flutter 01 目录结构入门

一、Flutter目录结构&#xff1a; 二、Flutter入口文件、入口方法&#xff1a; 三、Flutter Demo&#xff1a; demo1&#xff1a; import package:flutter/material.dart;//MaterialApp 和 Scaffold两个组件装饰App void main() {runApp(MaterialApp(home: Scaffold(appBar: A…

致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC]

文章目录 致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用…