引言
前面几篇文章都在介绍 Redis 原生命令行客户端,在实际应用开发中,开发人员更希望使用针对特定编程语言的专用客户端,通过编程的方式操作 Redis 数据库。因此,Redis 支持多种编程语言。本文将介绍 如何使用 C++ 语言来操作 Redis。
一、认识 RESP 协议
RESP(Redis serialization protocol)是 Redis 自定义的应用层协议,所有编程语言的 Redis 库都是基于这个协议开发的。它设计的核心目标是简单易实现、解析高效,同时兼顾人类可读性,使得开发者能轻松调试 Redis 通信过程。这里仅做简单介绍,详细内容可参考Redis 官方文档 :Redis 的 RESP 协议
1. RESP 协议的核心特点
- 文本协议:基于 ASCII 字符编码,协议内容可直接通过肉眼识别(区别于二进制协议),便于调试。
- 类型明确:通过特定前缀字符标识数据类型(如字符串、整数、数组等),解析时无需额外判断。
- 高效解析:协议格式规则简单,解析器可通过线性扫描快速处理,几乎无性能开销。
- 扩展性强:支持复杂数据结构(如嵌套数组),能满足 Redis 多样化命令和返回值的需求。
- 一问一答式:客户端一次请求,服务器就会回答一次
2. RESP 协议的基本数据类型及格式
RESP 通过首字符区分数据类型,常见类型及格式如下:
| 类型 | 前缀字符 | 格式说明 | 示例 | |
|---|---|---|---|---|
| 简单字符串 | + | +字符串内容\r\n(不含换行符,用于返回简单结果,如 “OK”) | +OK\r\n | |
| 错误消息 | - | -错误类型: 错误描述\r\n(用于返回错误信息,如命令不存在) | -ERR unknown command 'foo'\r\n | |
| 整数 | : | :整数数值\r\n(用于返回计数、状态码等,如 EXISTS 命令的返回值) | :1\r\n(表示存在该键) | |
| 批量字符串 | $ | $长度\r\n内容\r\n(用于存储二进制安全的字符串,长度为 -1 表示空值) | $5\r\nhello\r\n(表示字符串 “hello”) | |
| 数组 | * | *元素数量\r\n元素1\r\n元素2\r\n...(可嵌套数组,用于表示命令或复杂返回值) | *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n(表示 SET mykey myvalue 命令) |
3.、Redis 命令的传输流程(基于 RESP)
Redis 客户端与服务器的通信均通过 RESP 协议完成,以 SET mykey "hello" 命令为例,流程如下:
-
客户端发送命令:
命令以数组类型传输,数组元素为命令名和参数(均为批量字符串):*3\r\n // 数组包含3个元素(SET、mykey、hello) $3\r\nSET\r\n // 第一个元素:命令名 "SET"(长度3) $5\r\nmykey\r\n // 第二个元素:键 "mykey"(长度5) $5\r\nhello\r\n // 第三个元素:值 "hello"(长度5) -
服务器返回结果:
若命令执行成功,返回简单字符串+OK\r\n;若失败,返回错误消息(如-ERR syntax error\r\n)。
4. RESP 协议的优势与适用场景
-
优势:
- 实现简单:开发者可快速编写解析器(无需处理复杂的二进制格式)。
- 调试友好:通过
telnet或nc等工具可直接发送 RESP 格式命令与 Redis 交互(如telnet localhost 6379后输入*2\r\n$4\r\nPING\r\n$0\r\n\r\n测试连接)。 - 兼容性强:支持所有 Redis 命令及返回值类型,包括复杂结构(如
HGETALL返回的键值对数组)。
-
适用场景:
- 所有 Redis 客户端与服务器的通信(如 C++ 的 redisplusplus、Python 的
redis-py、Java 的Jedis等均基于 RESP 实现)。 - 自定义 Redis 客户端开发(需严格遵循 RESP 格式组装命令和解析响应)。
- 所有 Redis 客户端与服务器的通信(如 C++ 的 redisplusplus、Python 的
我们实际使用时,不需要按照协议自动组织,只需要使用Redis 官方提供或者大佬们开源的库就可以,我们接下来将使用 redis-plus-plus 库,它是 C++ 语言的 Redis库
二、ubuntu 安装 redis-plus-plus
1. 安装 hiredis
hiredis 是 Redis 官方为 c 语言提供的客户端支持,是redis-plus-plus 必备的依赖库
通过包管理器来安装:
sudo apt install libhiredis-dev
2.安装 redis-plus-plus
只能通过源码编译的方式安装
git clone https://github.com/sewenew/redis-plus-plus.git
cd redis-plus-plus
mkdir build
cd build
cmake ..
make
sudo make install
cd ..
依次执行完命令就安装好了,然后创建的这些目录我们都可以直接删除了
三、c++ 操作 Redis
环境安装好了,我们就可以通过编写 C++ 代码来操作 Redis 了
1. c++ redis的第一个程序
hello.cc
#include <sw/redis++/redis++.h>
#include <sw/redis++/redis.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::unordered_map;
using std::vector;
int main()
{
// 创建 Redis 对象,需指定 Redis服务器ip地址和端口
sw::redis::Redis redis("tcp://127.0.0.1:6379");
// 调用 ping 方法,让客户端发送一个 ping 命令,服务端会返回一个 pong
std::string result = redis.ping();
std::cout << result << std::endl;
return 0;
}
这段代码就是创建一个 Redis 对象,然后向 Redis 服务器发送一个 ping 命令,于是 Redis 服务器就会返回一个 pong 。
Makefile编写
我们需要注意 makefile 编写中需要指定库的位置,否则无法编译
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello
编译运行:

至此,使用 c++ 操作 Redis 的第一个程序就完成了!
2. 使用 c++ 执行 Redis 通用命令
代码框架
#include <sw/redis++/redis++.h>
#include <sw/redis++/redis.h>
#include <iostream>
#include <string>
void test()
{
// 每个命令写在这里
// ...
}
int main()
{
sw::redis::Redis redis("tcp://127.0.0.1:6379");
return 0;
}
首先给出代码框架,后续测试命令都会新创建一个 test 函数,然后再主函数中调用
Makefile:
.PHONY:all
all: hello generic
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic
get 和 set
set接口

可以看到这些参数和set命令的选项有很大关联:
- StringView 类型是 redis-plus-plus 提供的只读字符串,不能修改,这是由于只读字符产效率更高
- 参数 key 和 参数 val: 都是 StringView 类型
- 参数 ttl:以毫秒为单位的过期时间
- updatetype : 相当于 NX 和 XX
get接口

- get的返回值是 OptionalString,这个类型会对 空值 (nil)做特殊处理,c++ 14后也引入了 std::optional_string,具体用法见示例代码。
// get 和 set
void test1(sw::redis::Redis &redis)
{
std::cout << "get 和 set 的使用" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 使用 set 设置几个 key
redis.set("key1", "111");
// 使用 get 获取到 key 对应的 value
auto value1 = redis.get("key1");
if (value1)
{
std::cout << "value1=" << value1.value() << std::endl;
}
// key2 是空值,这里如果不加判断会抛出异常
auto value2 = redis.get("key2");
if (value2)
{
std::cout << "value2=" << value2.value() << std::endl;
}
}
运行结果(不要忘记在主函数中调用exists):
value2是空值,由于if语句,不会输出

exists

返回类型是 long long,支持查询多个key,返回存在的个数
generic.cc
// exists 命令
void test2(sw::redis::Redis &redis)
{
std::cout << "exists 的 使用" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");
auto ret = redis.exists("key1");
std::cout << ret << std::endl;
ret = redis.exists("key3");
std::cout << ret << std::endl;
ret = redis.exists({"key1", "key2", "key3"});
std::cout << ret << std::endl;
}
运行结果(记得在主函数中调用):

del
返回删除成功的个数
// del 命令
void test3(sw::redis::Redis &redis)
{
std::cout << "del 的使用" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");
auto ret = redis.del({"key1", "key2", "key3"});
std::cout << ret << std::endl;
ret = redis.exists({"key1", "key2", "key3"});
std::cout << ret << std::endl;
}
运行结果:

keys

- 参数 pattern : 匹配规则
- 参数 output: 插入迭代器,我们可以事先构建一个容器,传入迭代器,这样 keys就会把查询到的元素插入容器中
// keys 命令
void test4(sw::redis::Redis &redis)
{
std::cout << "keys 的使用" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "value1");
redis.set("key2", "value2");
redis.set("key3", "value2");
redis.set("key4", "value2");
redis.set("key5", "value2");
// redis 的keys 有两个参数,第一个是匹配规则
// 第二个是 “插入迭代器”,我们可以事先构建一个容器,传入迭代器
// 这样 keys就会把查询到的元素插入容器中
std::vector<std::string> result;
auto it = std::back_inserter(result);
redis.keys("*", it);
// 打印容器相关内容
for (auto &str : result)
{
std::cout << str << std::endl;
}
}
expire 和 ttl
// expire and ttl
void test5(sw::redis::Redis &redis)
{
std::cout << "expire and ttl" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "111");
redis.expire("key1", std::chrono::seconds(10));
std::this_thread::sleep_for(std::chrono::seconds(5));
long long ret = redis.ttl("key1");
std::cout << "剩余时间: " << ret << std::endl;
}

type
返回值是string类型
// type
void test6(sw::redis::Redis &redis)
{
std::cout << "type" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "111");
redis.lpush("key2", "111");
std::cout << redis.type("key1") << std::endl;
std::cout << redis.type("key2") << std::endl;
}
执行结果:

3. String
代码框架
#include <sw/redis++/cxx_utils.h>
#include <sw/redis++/redis++.h>
#include <sw/redis++/redis.h>
#include <iostream>
#include <iterator>
#include <vector>
// mget 和 mset
void test1(sw::redis::Redis& redis)
{
}
int main()
{
sw::redis::Redis redis("tcp://127.0.0.1:6379");
// test1(redis);
// test2(redis);
test3(redis);
return 0;
}
Makefile:
.PHONY:all
all: hello generic string
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
string:string.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic string
mset 和 mget
支持一次性设置多个值和获取多个值
// mget 和 mset
void test1(sw::redis::Redis& redis)
{
std::cout << "mget 和 mset" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 第一种方法,直接使用初始化列表
// redis.mset({std::make_pair("key1", "1"), std::make_pair("key2", "2"),
// std::make_pair("key3", "3")});
// 第二种方法,通过迭代器构造
std::vector<std::pair<std::string, std::string>> keys = {
{"key1", "111"}, {"key2", "222"}, {"key3", "333"}};
redis.mset(keys.begin(), keys.end());
std::vector<sw::redis::OptionalString> results;
auto it = std::back_inserter(results);
redis.mget({"key1", "key2", "key3"}, it);
for (auto& str : results)
{
if (str)
{
std::cout << str.value() << std::endl;
}
}
}
- mset 支持两种方式设置:
- 一是直接通过初始化列表传入pair
- 二是构造一个容器,传入迭代器
- mget 返回值是 OptionalString 也是通过插入迭代器的方式进行实现

getrange 和 setrange
void test2(sw::redis::Redis& redis)
{
std::cout << "mget 和 mset" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key", "abcdefghjk");
std::string result = redis.getrange("key", 2, 5);
std::cout << "result: " << result << std::endl;
redis.setrange("key", 2, "xyz");
result = redis.getrange("key", 0, -1);
std::cout << "result: " << result << std::endl;
}
运行结果:

incr 和 decr
// incr decr
void test3(sw::redis::Redis& redis)
{
std::cout << "incr 和 decr" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.set("key1", "100");
redis.set("key2", "100");
redis.incr("key1");
redis.decr("key2");
std::cout << redis.get("key1").value() << std::endl;
std::cout << redis.get("key2").value() << std::endl;
}
运行结果:

4. List
代码框架
#include <sw/redis++/redis++.h>
#include <sw/redis++/redis.h>
#include <iostream>
#include <iterator>
int main()
{
sw::redis::Redis redis("tcp://127.0.0.1:6379");
// test1(redis);
// test2(redis);
test3(redis);
return 0;
}
Makefile:
.PHONY:all
all: hello generic string list
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
string:string.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
list:list.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic string list
lpush 和 lrange
// lpush 和 lrange
void test1(sw::redis::Redis& redis)
{
std::cout << "lpush and lrange" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 插入单个元素
redis.lpush("key", "1");
// 插入一组元素,基于初始化列表
redis.lpush("key", {"2", "3", "4"});
// 插入一组元素,基于迭代器
std::vector<std::string> values = {"5", "6", "7"};
redis.lpush("key", values.begin(), values.end());
// lrange 获取结果,需要构造容器,传入插入迭代器
std::vector<std::string> results;
auto it = std::back_inserter(results);
redis.lrange("key", 0, -1, it);
// 打印结果
for (auto& result : results)
{
std::cout << result << std::endl;
}
}

lpop 和 rpop
// lpop 和 rpop
void test2(sw::redis::Redis& redis)
{
std::cout << "lpop and rpop" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.rpush("key", {"1", "2", "3", "4", "5", "6", "7"});
auto ret = redis.lpop("key");
if (ret)
{
std::cout << "lpop: " << ret.value() << std::endl;
}
ret = redis.rpop("key");
if (ret)
{
std::cout << "rpop: " << ret.value() << std::endl;
}
}

// blpop
void test3(sw::redis::Redis& redis)
{
std::cout << "blpop" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
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 << "元素无效!" << std::endl;
}
}

一开始会阻塞住,直到我们往 key1 key2 key3之一插入一个值

5. Set
代码框架
.PHONY:all
all: hello generic string list set
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
string:string.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
list:list.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
set:set.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic string list set
sadd 和 smembers
// sadd smembers
void test1(sw::redis::Redis &redis)
{
std::cout << "sadd and smembers" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 一次添加一个元素
redis.sadd("key", "111");
// 一次添加多个元素(使用初始化列表)
redis.sadd("key", {"222", "333"});
// 一次添加多个元素(使用迭代器)
std::vector<std::string> elems = {"444", "555"};
redis.sadd("key", elems.begin(), elems.end());
// 通过 smembers 获取返回结果
// 1. vector
// 2. set
// std::vector<std::string> results;
// auto it = std::back_inserter(results);
std::set<std::string> results;
auto it = std::inserter(results, results.end());
redis.smembers("key", it);
// 打印结果
for (auto &res : results)
{
std::cout << res << std::endl;
}
}

sismember 和 spop
// sismember and spop
void test2(sw::redis::Redis &redis)
{
std::cout << "sismember and spop" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.sadd("key", {"111", "222", "333"});
bool result = redis.sismember("key", "111");
std::cout << result << std::endl;
redis.spop("key");
redis.spop("key");
redis.spop("key");
result = redis.sismember("key", "111");
std::cout << result << std::endl;
}
运行结果:

sinter 和 sinterstore
// sinter
void test3(sw::redis::Redis &redis)
{
std::cout << "sinter" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.sadd("key1", {"111", "222", "333"});
redis.sadd("key2", {"111", "222", "444"});
std::set<std::string> results;
auto it = std::inserter(results, results.end());
redis.sinter({"key1", "key2"}, it);
for (auto &result : results)
{
std::cout << result << std::endl;
}
}
// sinterstore
void test4(sw::redis::Redis &redis)
{
std::cout << "sinterstore" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
redis.sadd("key1", {"111", "222", "333"});
redis.sadd("key2", {"111", "222", "444"});
long long len = redis.sinterstore("key3", {"key1", "key2"});
std::cout << "len: " << len << std::endl;
std::set<std::string> results;
auto it = std::inserter(results, results.end());
redis.smembers("key3", it);
// 打印结果
for (auto &res : results)
{
std::cout << res << std::endl;
}
}

6. Hash
代码框架
.PHONY:all
all: hello generic string list set hash
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
string:string.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
list:list.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
set:set.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
hash:hash.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic string list set hash
hset 和 hget
// hget and hset
void test1(sw::redis::Redis &redis)
{
std::cout << "hget and hset" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 插入一个 field-value 对
redis.hset("key", "f1", "1");
// 插入多个 field-value 对(初始化列表)
redis.hset("key", {std::make_pair("f2", "2"), std::make_pair("f3", "3")});
// 插入多个 field-value 对(迭代器)
std::vector<std::pair<std::string, std::string>> fields = {
std::make_pair("f4", "4"), std::make_pair("f5", "5")};
auto result = redis.hget("key", "f1");
if (result)
{
std::cout << result.value() << std::endl;
}
else
{
std::cout << "返回值无效!" << std::endl;
}
}

hexists,hdel 和 hlen
// hexists, hlen, hdel
void test2(sw::redis::Redis &redis)
{
std::cout << "hget and hset" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 插入多个 field-value 对(初始化列表)
redis.hset("key", {std::make_pair("f2", "2"), std::make_pair("f3", "3")});
std::cout << "删除前:" << std::endl;
long long len = redis.hlen("key");
std::cout << "len: " << len << std::endl;
bool result = redis.hexists("key", "f2");
std::cout << result << std::endl;
redis.hdel("key", "f2");
std::cout << "删除后:" << std::endl;
len = redis.hlen("key");
std::cout << "len: " << len << std::endl;
result = redis.hexists("key", "f2");
std::cout << result << std::endl;
}

hkeys 和 hvals
// hkeys
// hkeys hvals
void test3(sw::redis::Redis &redis)
{
std::cout << "keys hvals" << std::endl;
// 清空一下数据库,避免之前数据的干扰,生产环境禁用!
redis.flushall();
// 插入多个 field-value 对(初始化列表)
redis.hset("key", {std::make_pair("f1", "1"), std::make_pair("f2", "2"),
std::make_pair("f3", "3")});
std::vector<std::string> fields;
auto it = std::back_inserter(fields);
redis.hkeys("key", it);
for (auto &str : fields)
{
std::cout << str << std::endl;
}
std::vector<std::string> vals;
it = std::back_inserter(vals);
redis.hvals("key", it);
for (auto &str : vals)
{
std::cout << str << std::endl;
}
}

7. Zset
.PHONY:all
all: hello generic string list set hash zset
hello:hello.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
generic:generic.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
string:string.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
list:list.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
set:set.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
hash:hash.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
zset:zset.cc
g++ -std=c++17 -o $@ $^ /usr/local/lib/libredis++.a /usr/lib/x86_64-linux-gnu/libhiredis.a -pthread
PHONY:clean
clean:
rm -rf hello generic string list set hash zset
zadd 和 zrange
zrange 查询是否带分数取决于插入迭代器对应容器的类型:
- 如果插入迭代器对应一个仅包含 string 的类型的容器
- 如果插入迭代器对应容器是
pair<string, double>为元素的容器,则返回分数
// zadd zrange
void test1(sw::redis::Redis& redis)
{
std::cout << "zadd zrange" << std::endl;
// 清空数据库,防止之前的数据干扰,生产环境禁用!
redis.flushall();
// 三种版本
redis.zadd("key", "吕布", 99);
redis.zadd("key", {std::make_pair("赵云", 98), std::make_pair("张飞", 95)});
std::vector<std::pair<std::string, double>> members = {
std::make_pair("典韦", 97), std::make_pair("关羽", 96)};
redis.zadd("key", members.begin(), members.end());
// zrange 是否查询分数要看容器类型
// 如果容器仅 string 则 仅查询member
// 如果容器是 pair<string, double>, 则返回member 和 分数
std::cout << "仅查询member" << std::endl;
std::vector<std::string> results;
auto it = std::back_inserter(results);
redis.zrange("key", 0, -1, it);
for (auto& s : results)
{
std::cout << s << std::endl;
}
std::cout << "查询member和分数" << std::endl;
std::vector<std::pair<std::string, double>> scores;
auto it1 = std::back_inserter(scores);
redis.zrange("key", 0, -1, it1);
for (auto& [member, score] : scores)
{
std::cout << member << " " << score << std::endl;
}
}

zcard zrank zscore
// zcard zscore zrank
void test2(sw::redis::Redis& redis)
{
std::cout << "zcard zscore zrank" << std::endl;
// 清空数据库,防止之前的数据干扰,生产环境禁用!
redis.flushall();
redis.zadd("key", "zhangsan", 90);
redis.zadd("key", "lisi", 91);
redis.zadd("key", "wangwu", 92);
redis.zadd("key", "zhaoliu", 93);
long long result = redis.zcard("key");
std::cout << result << std::endl;
auto score = redis.zscore("key", "zhangsan");
if (score)
{
std::cout << "score: " << score.value() << std::endl;
}
else
{
std::cout << "score 无效" << std::endl;
}
auto rank = redis.zrank("key", "lisi");
if (score)
{
std::cout << "rank: " << rank.value() << std::endl;
}
else
{
std::cout << "rank 无效" << std::endl;
}
}


2698

被折叠的 条评论
为什么被折叠?



