【Redis】C++操作redis

目录

  • redis-plus-plus
  • 通用指令
    • ping
    • [set / get](#set / get)
    • [del / exists](#del / exists)
    • keys
    • [expire / ttl](#expire / ttl)
    • type
  • string类型
    • [set / get](#set / get)
    • [mset / mget](#mset / mget)
    • [getrange / setrange](#getrange / setrange)
    • [incr / decr](#incr / decr)
  • list类型
    • [lpush / lrange](#lpush / lrange)
    • rpush
    • [lpop / rpop](#lpop / rpop)
    • [lbpop / rbpop](#lbpop / rbpop)
    • llen
  • set类型
    • [sadd / smembers](#sadd / smembers)
    • [sismember / spop / scard](#sismember / spop / scard)
    • [sinter / sinterstore](#sinter / sinterstore)
  • hash类型
    • [hset / hget](#hset / hget)
    • [hexists / hdel / hlen](#hexists / hdel / hlen)
    • [hkeys / hvals / hmget](#hkeys / hvals / hmget)
  • zset类型
    • [zadd / zrange](#zadd / zrange)
    • [zcard / zrem / zscore / zrank](#zcard / zrem / zscore / zrank)

redis-plus-plus

Redis 采用 RESP 协议进行客户端和服务端的通信,我们之前使用的 redis-cli 客户端也是用的这个协议,RESP 协议本身够简单够高效,使得很多语言可以很方便的开发对应的客户端。C++ 方面就已经有很多大佬开发出了很多成熟的库了,这里我们使用 redis-plus-plus,在 github 上可以很方便的搜到,之后配置一下就好了,环境的配置这块不过多介绍。

通用指令

ping

cpp 复制代码
std::string sw::redis::Redis::ping()

装好库了我们试一下 ping 指令,使用 redis-plus-plus 库我们先要包头文件,

cpp 复制代码
#include<sw/redis++/redis++.h>

因为其在系统默认路径 /usr/local/include/ 下,所以不需要在编译指令上额外加上头文件目录让其去找了,但是因为其在 /usr/local/include/ 下还有额外包了 sw/redis++/ 两个目录,所以头文件这里要这么写。

此外我们还要手动指定动态库的位置,因为动态库的位置不是系统默认路径,需要制定的分别是 redis++、hiredis、pthread,这里可以直接抄我的 Makefile。

bash 复制代码
test : test.cc
	g++ -o $@ $^ -std=c++17 -L /usr/lib/x86_64-linux-gnu -lhiredis -L /usr/local/lib -lredis++  -lpthread -Wl,-rpath=/usr/local/lib:/usr/lib/x86_64-linux-gnu

准备好了就能开始写了。

cpp 复制代码
#include<iostream>
#include<vector>
#include<unordered_map>
#include<string>
#include<sw/redis++/redis++.h>

void test1()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    std::string ret = redis.ping();
    std::cout << ret << std::endl;
}

int main()
{
    test1();
    return 0;
}

首先我们创建 sw::redis::Redis 类型的对象,然后传入要连接的 Redis 服务端的地址字符串,注意这是一个 url,url 并非 http 独有,前面换成 tcp 表示 tcp 协议,这里为什么不是 RESP 呢?RESP 是应用层,tcp 是网络层,RESP 用到了 TCP 但是与其并不强耦合,Redis 的通信本质是:基于 TCP 连接,传输符合 RESP 格式的字节数据,所以这里传 tcp 表示建立 tcp 连接。本地的就是环回地址,然后指定对应的端口,这个端口不改配置文件的话默认 6397。

之后我们就能通过这个对象的成员函数完成各种我们学习过的指令。这里我们先试一下 ping,正常应该返回 pong。对应到这个对象就是 ping 函数,返回字符串。这也顺便测试一下我们的环境配置代码编译选项各方面有没有出错。

set / get

cpp 复制代码
bool sw::redis::Redis::set(const sw::redis::StringView &key, const sw::redis::StringView &val, const std::chrono::milliseconds &ttl = ((std::chrono::milliseconds)(0)), sw::redis::UpdateType type = sw::redis::UpdateType::ALWAYS)
cpp 复制代码
sw::redis::OptionalString sw::redis::Redis::get(const sw::redis::StringView &key)

注意这里的参数和我们学过的指令息息相关,但是这里的字符串是 StringView,其实就是只读字符串,这个类型 C++17 中推出了,但是为了兼容 C++11,所以自定义了一个类型,多一层封装,如果是老版本,就用自己实现的,新版本的话直接在封装里面包官方的就行了。我们用就直接传字符串就行。

对于 get 的返回值,是 sw::redis::OptionalString,其实这也是一个字符串,可以表示无效值的字符串,因为 std::string 无法很好的表示无效值,所以 C++14 中推出了 optional 类型。同样为了兼容,搞了个自定义的。

cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");

sw::redis::OptionalString ret1 = redis.get("key1");
sw::redis::OptionalString ret2 = redis.get("key2");
sw::redis::OptionalString ret3 = redis.get("key3");
if(ret1) std::cout << ret1.value() << std::endl;
if(ret2) std::cout << ret2.value() << std::endl;
if(ret3) std::cout << ret3.value() << std::endl;

注意这里的 sw::redis::OptionalString 只是一个容器,不支持直接打印,我们要使用 value 函数取出来才行。另外,如果是非法的 sw::redis::OptionalString 取值,会抛出异常,所以我们可以预先判断一下,这个类型定义了 bool 的类型转换运算符,所以可以根据真假判断是否非法。

del / exists

cpp 复制代码
long long sw::redis::Redis::exists(const sw::redis::StringView &key)
cpp 复制代码
long long sw::redis::Redis::del(const sw::redis::StringView &key)
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");
redis.set("key3", "value3");

std::cout << redis.exists({"key1", "key2"}) << std::endl;
std::cout << redis.exists("key1") << std::endl << std::endl;
std::cout << redis.exists("key2") << std::endl << std::endl;

redis.del("key1");
std::cout << redis.exists("key1") << std::endl;
std::cout << redis.exists("key2") << std::endl << std::endl;

redis.del({"key1", "key2", "key3"});
std::cout << redis.exists("key1") << std::endl;
std::cout << redis.exists("key2") << std::endl;

del 返回 0 表示键不存在,1 表示存在而且已经删除(如果要穿多个参数可以用 std::initializer_list,也就是花括号包起来)。exists 返回 0 表示不存在,1 表示存在如果要穿多个参数可以用 std::initializer_list,也就是花括号包起来)。

keys

cpp 复制代码
void keys(const StringView &pattern, Output output);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");
redis.set("key3", "value3");

std::vector<std::string> arr;
auto it = std::back_inserter(arr);
redis.keys("*", it);
for(auto& e : arr)
    std::cout << e << std::endl;

这里用到了 back_insert_iterator,也就是插入迭代器,这是一种迭代器适配器,本质也是一种 "输出迭代器"。其作用是通过迭代器的形式,向容器的「尾部」插入元素。什么意思呢?这里我们通过 back_inserter 函数构造出了 arr 对象的插入迭代器,我们将这个迭代器传给 keys 函数,这时 keys 会用这个迭代器进行 *it = 值 的操作,其通过 = 运算符重载,将其变成将这个值 push_back 到 arr 中。对于 * 和 ++ 操作,其什么都不会做。为什么要这么设计呢?因为考虑到有些函数不关心传进来什么容器,只想将结果尾插(或其它操作)到容器中,不管什么容器,那么这时为了解耦考虑,设计这个迭代器适配器,函数中直接对其进行 *it = 值 操作,* 返回本身,= 重载成对应容器的尾插,那么这时就实现了解耦,我们想要尾插什么容器,直接构造对应的 back_insert_iterator 就行。

因为 back_insert_iterator 的构造方式比较复杂,我们就往往使用 std::back_inserter 辅助构造。此外,插入迭代器还有 front_insert_iterator(向容器的开头插入)、insert_iterator(区间的任意位置,向该位置之前进行插入)。

expire / ttl

cpp 复制代码
inline bool sw::redis::Redis::expire(const sw::redis::StringView &key, const std::chrono::seconds &timeout)
cpp 复制代码
long long sw::redis::Redis::ttl(const sw::redis::StringView &key);
cpp 复制代码
using namespace std::chrono_literals;
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.expire("key1", std::chrono::seconds(10)); // 10也行
std::this_thread::sleep_for(3s); // 3s需要展开std::chrono_literals命名空间
auto ret = redis.ttl("key1");
std::cout << ret << std::endl;
cpp 复制代码
using namespace std::chrono_literals;
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.expire("key1", std::chrono::seconds(10)); // 10也行
std::this_thread::sleep_for(3s); // 3也行,3s需要展开std::chrono_literals命名空间
auto ret = redis.ttl("key1");
std::cout << ret << std::endl;
std::this_thread::sleep_for(7s);
std::cout << redis.exists("key1") << std::endl;

这里的 expire 可以传秒数,秒数可以直接传数字,也能展开 std::chrono_literals 引入时间字面量直接使用 s,也能使用 std::chrono::seconds 函数构造。

type

cpp 复制代码
std::string sw::redis::Redis::type(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1");
redis.lpush("key2", "hello");
redis.hset("key3", "key1", "value1");
redis.sadd("key4", "hello");
std::cout << redis.type("key1") << std::endl;
std::cout << redis.type("key2") << std::endl;
std::cout << redis.type("key3") << std::endl;
std::cout << redis.type("key4") << std::endl;

string类型

set / get

cpp 复制代码
using namespace std::chrono_literals;
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "value1", 5s);
std::this_thread::sleep_for(6s);
auto ret = redis.get("key1");
if(ret) std::cout << ret.value() << std::endl;
redis.set("key2", "value2", 0s, sw::redis::UpdateType::EXIST);
ret = redis.get("key2");
if(ret) std::cout << ret.value() << std::endl;
redis.set("key3", "value3", 0s, sw::redis::UpdateType::NOT_EXIST);
ret = redis.get("key3");
if(ret) std::cout << ret.value() << std::endl;

这个通用指令中也讲过,这里补充一下超时时间设置和 XX / NX 选项的用法。首先超时时间直接在后面加,可以使用 chrono 的,也能直接传数字。然后对于 XX / NX,sw::redis::UpdateType 中有对应的选项:EXIST、NOT_EXIST、ALWAYS。对应 XX、NX、默认不传(也就是都要)。

mset / mget

cpp 复制代码
inline void sw::redis::Redis::mset<std::pair<std::string, std::string>>(std::initializer_list<std::pair<std::string, std::string>> il)
cpp 复制代码
void sw::redis::Redis::mset<std::vector<std::pair<std::string, std::string>>::iterator>(std::vector<std::pair<std::string, std::string>>::iterator first, std::vector<std::pair<std::string, std::string>>::iterator last)
cpp 复制代码
void mget(std::initializer_list<T> il, Output output)
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
// redis.mset({std::make_pair("key1", "value1"), std::make_pair("key2", "value2"), std::make_pair("key3", "value3")});
// redis.mset({std::pair<std::string, std::string>{"key1", "value1"}, 
//     {"key2", "value2"}, 
//     {"key3", "value3"}});
std::vector<std::pair<std::string, std::string>> arr{
    {"key1", "value1"},
    {"key2", "value2"},
    {"key3", "value3"}
};
redis.mset(arr.begin(), arr.end());
std::vector<sw::redis::OptionalString> buffer;
auto it = std::back_inserter(buffer);
redis.mget({ "key1", "key2", "key3", "key4" }, it);
for(auto& e : buffer)
    if(e) std::cout << e.value() << std::endl;
    else std::cout << "not exists." << std::endl;

我们既可以使用 std::initializer_list,也能用迭代器。mget 还是老样子,用的插入迭代器。

getrange / setrange

cpp 复制代码
std::string sw::redis::Redis::getrange(const sw::redis::StringView &key, long long start, long long end);
cpp 复制代码
long long sw::redis::Redis::setrange(const sw::redis::StringView &key, long long offset, const sw::redis::StringView &val);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "abcdefghij");
auto ret1 = redis.getrange("key1", 1, 3);
std::cout << ret1 << std::endl;
redis.setrange("key1", 3, "aaaaaaaaaaaaaaaaa");
auto ret2 = redis.get("key1");
if(ret2) std::cout << ret2.value() << std::endl;

incr / decr

cpp 复制代码
long long sw::redis::Redis::incr(const sw::redis::StringView &key);
cpp 复制代码
long long sw::redis::Redis::decr(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.set("key1", "1");
redis.incr("key1");
auto ret1 = redis.get("key1");
if(ret1) std::cout << ret1.value() << std::endl;
redis.decr("key1");
auto ret2 = redis.get("key1");
if(ret2) std::cout << ret2.value() << std::endl;

list类型

lpush / lrange

cpp 复制代码
long long sw::redis::Redis::lpush(const sw::redis::StringView &key, const sw::redis::StringView &val)
cpp 复制代码
template <typename T>
long long lpush(const StringView &key, std::initializer_list<T> il);
cpp 复制代码
template <typename Input>
inline long long Redis::lpush(const StringView &key, Input first, Input last);
cpp 复制代码
inline void Redis::lrange(const StringView &key, long long start, long long stop, Output output);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.lpush("mylist1", "hello");
redis.lpush("mylist1", { "world", "nihao", "redis"});
std::vector<std::string> arr{"111", "222", "333"};
redis.lpush("mylist1", arr.begin(), arr.end());
std::vector<std::string> back;
auto it = std::back_inserter(back);
redis.lrange("mylist1", 0, -1, it);
for(auto& e : back)
    std::cout << e << std::endl;

lpush 是头插,如果只想头插一个的话,那么可以只传一个 string,如果相传多个,可以使用 initializer_list 或者 迭代器表示。

rpush

cpp 复制代码
long long sw::redis::Redis::rpush(const sw::redis::StringView &key, const sw::redis::StringView &val);
cpp 复制代码
template <typename T>
long long rpush(const StringView &key, std::initializer_list<T> il);
cpp 复制代码
template <typename Output>
inline void Redis::lrange(const StringView &key, long long start, long long stop, Output output);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.rpush("mylist1", "hello");
redis.rpush("mylist1", { "world", "nihao", "redis"});
std::vector<std::string> arr{"111", "222", "333"};
redis.rpush("mylist1", arr.begin(), arr.end());
std::vector<std::string> back;
auto it = std::back_inserter(back);
redis.lrange("mylist1", 0, -1, it);
for(auto& e : back)
    std::cout << e << std::endl;

和 lpush 一致。

lpop / rpop

cpp 复制代码
sw::redis::OptionalString sw::redis::Redis::lpop(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::OptionalString sw::redis::Redis::rpop(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.lpush("mylist1", { "1", "2", "3", "4"});
sw::redis::OptionalString ret1 = redis.lpop("mylist1");
if(ret1) std::cout << ret1.value() << std::endl;
sw::redis::OptionalString ret2 = redis.rpop("mylist1");
if(ret2) std::cout << ret2.value() << std::endl;

lbpop / rbpop

cpp 复制代码
OptionalStringPair blpop(std::initializer_list<T> il,
                            const std::chrono::seconds &timeout = std::chrono::seconds{0});
cpp 复制代码
OptionalStringPair brpop(std::initializer_list<T> il,
                            const std::chrono::seconds &timeout = std::chrono::seconds{0});
cpp 复制代码
using namespace std::chrono_literals;
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
auto ret = redis.blpop({ "key1", "key2", "key3" });
if(ret)
{
    std::cout << "key: " << ret.value().first << std::endl;
    std::cout << "elem: " << ret.value().second << std::endl;
}
else
{
    std::cout << "result error" << std::endl;
}

这里 lbpop / rbpop 原理一致。返回值是一个 optional,里面报了一个 pair,第一个元素表示其从属于哪个list,第二个是当前被删除的元素。因为有超时时间,所以会有超时返回无效值的情况。等待的多个 key 可以用 initializer_list 或容器迭代器表示,超时时间可以设置,也可以不设置,不设置默认 0s,也就是永久阻塞。

llen

cpp 复制代码
long long sw::redis::Redis::llen(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.lpush("key1", {"1", "2", "3"});
auto ret = redis.llen("key1");
std::cout << ret << std::endl;

set类型

sadd / smembers

cpp 复制代码
long long sw::redis::Redis::sadd(const sw::redis::StringView &key, const sw::redis::StringView &member);
cpp 复制代码
long long sadd(const StringView &key, std::initializer_list<T> il);
cpp 复制代码
long long Redis::sadd(const StringView &key, Input first, Input last);
cpp 复制代码
void Redis::smembers(const StringView &key, Output output);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.sadd("myset1", "1");
redis.sadd("myset1", {"2", "3", "4"});
std::vector<std::string> arr{"5", "6", "7"};
redis.sadd("myset1", arr.begin(), arr.end());

// std::vector<std::string> ret;
// auto it = std::back_inserter(ret);
std::set<std::string> ret;
auto it = std::inserter(ret, ret.end());
redis.smembers("myset1", it);
for(auto& e : ret)
    std::cout << e << std::endl;

注意这里的 smembers 我们尝试使用 set 去存储时,不要使用尾插迭代器,因为 set 没有 push_back 的接口,尾插迭代器会去调用 push_back。我们使用指定位置之后插入的迭代器,辅助构造的函数是 inserter。

sismember / spop / scard

cpp 复制代码
bool sw::redis::Redis::sismember(const sw::redis::StringView &key, const sw::redis::StringView &member)
cpp 复制代码
long long sw::redis::Redis::scard(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::OptionalString sw::redis::Redis::spop(const sw::redis::StringView &key)
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.sadd("myset1", {"1", "2", "3"});
std::cout << redis.sismember("myset1", "2") << std::endl;
std::cout << redis.sismember("myset1", "4") << std::endl;
std::cout << redis.scard("myset1") << std::endl;
auto ret = redis.spop("myset1");
if(ret) std::cout << ret.value() << std::endl;

sinter / sinterstore

cpp 复制代码
template <typename T, typename Output>
    void sinter(std::initializer_list<T> il, Output output);
cpp 复制代码
template <typename Input, typename Output>
	void sinter(Input first, Input last, Output output);
cpp 复制代码
long long sinterstore(const StringView &destination, std::initializer_list<T> il)
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.sadd("myset1", {"1", "2", "3"});
redis.sadd("myset2", {"2", "3", "4"});
std::set<std::string> ret1;
auto it = std::inserter(ret1, ret1.end());
redis.sinter({"myset1", "myset2"}, it);
for(auto& e : ret1)
    std::cout << e << std::endl;
std::cout << std::endl;
std::cout << redis.sinterstore("myset3", {"myset1", "myset2"}) << std::endl << std::endl;
std::set<std::string> ret2;
it = std::inserter(ret2, ret2.end());
redis.smembers("myset3", it);
for(auto& e : ret2)
    std::cout << e << std::endl;

hash类型

hset / hget

cpp 复制代码
long long sw::redis::Redis::hset(const sw::redis::StringView &key, const sw::redis::StringView &field, const sw::redis::StringView &val)
cpp 复制代码
long long sw::redis::Redis::hset(const sw::redis::StringView &key, const std::pair<sw::redis::StringView, sw::redis::StringView> &item);
cpp 复制代码
long long hset(const StringView &key, std::initializer_list<T> il);
cpp 复制代码
long long sw::redis::Redis::hset(const sw::redis::StringView &key, const sw::redis::StringView &field, const sw::redis::StringView &val);
cpp 复制代码
sw::redis::OptionalString sw::redis::Redis::hget(const sw::redis::StringView &key, const sw::redis::StringView &field);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.hset("myhash1", "f1", "1");
redis.hset("myhash1", std::make_pair("f2", "2"));
redis.hset("myhash1", {std::make_pair("f3", "3"), std::make_pair("f4", "4")});
std::vector<std::pair<std::string, std::string>> arr{std::make_pair("f5", "5"), std::make_pair("f6", "6")};
redis.hset("myset1", arr.begin(), arr.end());
auto ret = redis.hget("myhash1", "f1");
if(ret) std::cout << ret.value() << std::endl;

hexists / hdel / hlen

cpp 复制代码
bool sw::redis::Redis::hexists(const sw::redis::StringView &key, const sw::redis::StringView &field);
cpp 复制代码
long long sw::redis::Redis::hdel(const sw::redis::StringView &key, const sw::redis::StringView &field);
cpp 复制代码
long long sw::redis::Redis::hlen(const sw::redis::StringView &key);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.hset("myhash1", {std::make_pair("f1", "1"), std::make_pair("f2", "2"), std::make_pair("f3", "3")});
std::cout << redis.hexists("myhash1", "f1") << std::endl;
std::cout << redis.hdel("myhash1", "f1") << std::endl;
std::cout << redis.hlen("myhash1") << std::endl;

hkeys / hvals / hmget

cpp 复制代码
template <typename Output>
inline void Redis::hkeys(const StringView &key, Output output);
cpp 复制代码
template <typename Output>
inline void Redis::hvals(const StringView &key, Output output);
cpp 复制代码
void hmget(const StringView &key, std::initializer_list<T> il, Output output)
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.hset("myhash1", {std::make_pair("f1", "1"), std::make_pair("f2", "2"), std::make_pair("f3", "3")});
std::vector<std::string> ret1;
auto it = std::back_inserter(ret1);
redis.hkeys("myhash1", it);
redis.hvals("myhash1", it);
for(auto& e : ret1)
    std::cout << e << std::endl;
std::cout << std::endl;
std::vector<std::string> ret2;
it = std::back_inserter(ret2);
redis.hmget("myhash1", {"f1", "f2"}, it);
for(auto& e : ret2)
    std::cout << e << std::endl;

zset类型

zadd / zrange

cpp 复制代码
long long Redis::zadd(const StringView &key, Input first, Input last, UpdateType type, bool changed);
cpp 复制代码
long long zadd(const StringView &key, std::initializer_list<T> il, UpdateType type = UpdateType::ALWAYS, bool changed = false);
cpp 复制代码
long long Redis::zadd(const StringView &key, Input first, Input last, UpdateType type, bool changed);
cpp 复制代码
template <typename Output>
void Redis::zrange(const StringView &key, long long start, long long stop, Output output);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.zadd("myzset1", "a", 1);
redis.zadd("myzset1", {
    std::make_pair("b", 2),
    std::make_pair("c", 3)
});
std::vector<std::pair<std::string, double>> arr{
    std::make_pair("d", 4),
    std::make_pair("e", 5)
};
redis.zadd("myzset1", arr.begin(), arr.end());
std::vector<std::string> ret1;
auto it1 = std::back_inserter(ret1);
redis.zrange("myzset1", 0, -1, it1);
for(auto& e : ret1)
    std::cout << e << std::endl;
std::cout << std::endl;
std::vector<std::pair<std::string, double>> ret2;
auto it2 = std::back_inserter(ret2);
redis.zrange("myzset1", 0, -1, it2);
for(auto& e : ret2)
    std::cout << e.first << " " << e.second << std::endl;

注意 zrange 可以根据插入迭代器对应的容器类型选择不同的输出方式,因为 zset 有 member 和 score,如果只是一个 string 的容器,那么就会输出 member,如果是 pair,那么就会输出 member 和 score。

zcard / zrem / zscore / zrank

cpp 复制代码
long long sw::redis::Redis::zcard(const sw::redis::StringView &key);
cpp 复制代码
long long sw::redis::Redis::zrem(const sw::redis::StringView &key, const sw::redis::StringView &member);
cpp 复制代码
sw::redis::OptionalDouble sw::redis::Redis::zscore(const sw::redis::StringView &key, const sw::redis::StringView &member);
cpp 复制代码
sw::redis::Redis redis("tcp://127.0.0.1:6379");
redis.flushall();
redis.zadd("myzset1", {
    std::make_pair("a", 1),
    std::make_pair("b", 2),
    std::make_pair("c", 3)
});
redis.zrem("myzset1", "a");
std::cout << redis.zcard("myzset1") << std::endl;
auto score = redis.zscore("myzset1", "b");
if(score) std::cout << score.value() << std::endl;
auto rank = redis.zrank("myzset1", "b");
if(rank) std::cout << rank.value() << std::endl;
相关推荐
小高不会迪斯科7 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
寻寻觅觅☆7 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc8 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
e***8908 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t8 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
ceclar1239 小时前
C++使用format
开发语言·c++·算法
失忆爆表症9 小时前
03_数据库配置指南:PostgreSQL 17 + pgvector 向量存储
数据库·postgresql
AI_56789 小时前
Excel数据透视表提速:Power Query预处理百万数据
数据库·excel
lanhuazui109 小时前
C++ 中什么时候用::(作用域解析运算符)
c++
charlee449 小时前
从零实现一个生产级 RAG 语义搜索系统:C++ + ONNX + FAISS 实战
c++·faiss·onnx·rag·语义搜索