目录1. 安装与编译1.1. 安装 hiredis1.2. 下载并编译 redis-plus-plus1.3. 编译自己的程序2. 连接 Redis单机连接集群连接3. 常用接口速查表3.1. 通用命令 Generic3.2. 字符串 String3.3. 列表 List3.4. 集合 Set3.5 哈希 Hash3.6 有序集合 Zset3.7 示例4. Optional 返回值必须判断4.1. Optional 返回值4.2 不同 Optional 类型的判断和取值4.3 关于 value() 和 operator-5. 批量操作使用迭代器5.1 两个核心插入迭代器back_inserter 用法inserter 用法redis-plus-plus 让 C 操作 Redis 非常接近原生命令安装 hiredis、编译 redis-plus-plus、链接 libredis.a 后即可通过 sw::redis::Redis 或 sw::redis::RedisCluster 快速接入。掌握 Optional 判断、迭代器批量读写、过期时间、NX/XX、异常处理等要点后可以在 C 项目中高效使用 Redis。redis-plus-plus GitHubsewenew/redis-plus-plus: Redis client written in CAPI 地址redis-plus-plus/src/sw/redis/redis.h at master · sewenew/redis-plus-plus1. 安装与编译1.1. 安装 hiredisredis-plus-plus 依赖 hiredis先通过包管理器安装需要有 root 权限系统安装命令Ubuntuapt install libhiredis-devCentOSyum install hiredis-devel.x86_641.2. 下载并编译 redis-plus-plusgit clone https://github.com/sewenew/redis-plus-plus.git cd redis-plus-plus mkdir build cd build Ubuntu cmake .. make sudo make install CentOS 自带 cmake 版本较低使用 cmake3 yum install cmake3 cmake3 .. make sudo make install安装成功后头文件/usr/local/include/sw/redis/库文件/usr/local/lib/ 或 /usr/local/lib64/ 下的 libredis.a1.3. 编译自己的程序Ubuntu 示例 g -stdc17 -g -O0 -o demo demo.cc \ /usr/local/lib/libredis.a \ /lib/x86_64-linux-gnu/libhiredis.a -pthread CentOS 示例 g -stdc17 -g -O0 -o demo demo.cc \ /usr/local/lib64/libredis.a \ /usr/local/lib/libhiredis.a -pthread不同系统库路径可能不同链接时务必确认 libredis.a 与 libhiredis.a 的实际位置并加上 -pthread2. 连接 Redis单机连接#include sw/redis/redis.h using sw::redis::Redis; int main() { Redis redis(tcp://127.0.0.1:6379); redis.set(k1, 111); auto value redis.get(k1); if (value) { printf(value: %s\n, value-c_str()); } return 0; }集群连接只需将 Redis 替换为 RedisCluster构造参数填入集群中任意节点地址#include sw/redis/redis.h using sw::redis::RedisCluster; int main() { RedisCluster cluster(tcp://127.0.0.1:6379); cluster.set(k1, 111); auto value cluster.get(k1); if (value) { printf(value: %s\n, value-c_str()); } return 0; }3. 常用接口速查表3.1. 通用命令 GenericRedis 命令C 接口示例返回值/说明EXISTSredis.exists(key)long longEXISTS 多 keyredis.exists({key1,key2})long longDELredis.del({key1,key2})long longKEYSredis.keys(*name*, std::back_inserter(keys))通过插入迭代器输出EXPIREredis.expire(key, std::chrono::seconds(10))boolTTLredis.ttl(key)long longPTTLredis.pttl(key)long longTYPEredis.type(key)std::stringFLUSHDBredis.flushdb()清空当前库3.2. 字符串 StringRedis 命令C 接口示例返回值/说明SETredis.set(key, Hello)boolSET NX/XXredis.set(key,World, std::chrono::seconds(0), sw::redis::UpdateType::NOT_EXIST)boolGETauto v redis.get(key)OptionalStringAPPENDredis.append(key, World)long longGETRANGEredis.getrange(key, 0, 3)std::stringSETEXredis.setex(key, std::chrono::seconds(10), Hello)voidPSETEXredis.psetex(key, std::chrono::milliseconds(10000), Hello)voidSETNXredis.setnx(key, Hello)long longDECRredis.decr(key)long longDECRBYredis.decrby(key, 3)long longINCRredis.incr(key)long longINCRBYredis.incrby(key, 3)long longINCRBYFLOATredis.incrbyfloat(key, 0.1)doubleMGETredis.mget({key1,key2}, std::back_inserter(values))输出OptionalString列表MSETredis.mset(kvs.begin(), kvs.end())voidMSETNXredis.msetnx(kvs.begin(), kvs.end())boolSETRANGEredis.setrange(key, 6, Redis)long longSTRLENredis.strlen(key)long long3.3. 列表 ListRedis 命令C 接口示例返回值/说明LPUSHredis.lpush(list, world)long longLPUSHXredis.lpushx(list, hello)long longRPUSHredis.rpush(list, {a,b,c})long longRPUSHXredis.rpushx(list, hello)long longLRANGEredis.lrange(list, 0, -1, std::back_inserter(elems))输出列表LPOPauto v redis.lpop(list)OptionalStringBLPOPauto p redis.blpop({list1,list2}, std::chrono::seconds(5))OptionalStringPairRPOPauto v redis.rpop(list)OptionalStringBRPOPauto p redis.brpop({list1,list2}, std::chrono::seconds(5))OptionalStringPairLINDEXauto v redis.lindex(list, 0)OptionalStringLINSERTredis.linsert(list, sw::redis::InsertPosition::BEFORE, World, There)long longLLENredis.llen(list)long long3.4. 集合 SetRedis 命令C 接口示例返回值/说明SADDredis.sadd(set, Hello)long longSMEMBERSredis.smembers(set, std::inserter(elements, elements.begin()))输出集合SISMEMBERredis.sismember(set, one)boolSCARDredis.scard(set)long longSPOPauto v redis.spop(set)或redis.spop(set, 3, std::inserter(poped, poped.begin()))OptionalString或输出集合SMOVEredis.smove(src, dst, member)boolSREMredis.srem(set, one)long longSINTERredis.sinter({key1,key2}, std::inserter(elements, elements.begin()))输出交集SINTERSTOREredis.sinterstore(dest, {key1,key2})long longSUNIONredis.sunion({key1,key2}, std::inserter(elements, elements.begin()))输出并集SUNIONSTOREredis.sunionstore(dest, {key1,key2})long longSDIFFredis.sdiff({key1,key2}, std::inserter(elements, elements.begin()))输出差集SDIFFSTOREredis.sdiffstore(dest, {key1,key2})long long3.5 哈希 HashRedis 命令C 接口示例返回值/说明HSETredis.hset(key, name, zhangsan)bool/long longHGETauto v redis.hget(key, name)OptionalStringHEXISTSredis.hexists(key, name)boolHDELredis.hdel(key, name)long longHKEYSredis.hkeys(key, std::back_inserter(keys))输出字段列表HVALSredis.hvals(key, std::back_inserter(values))输出值列表HMGETredis.hmget(key, fields.begin(), fields.end(), std::back_inserter(values))输出OptionalString列表HLENredis.hlen(key)long longHINCRBYredis.hincrby(key, age, 10)long longHINCRBYFLOATredis.hincrbyfloat(key, age, 0.5)double3.6 有序集合 ZsetRedis 命令C 接口示例返回值/说明ZADDredis.zadd(key, 吕布, 100)long longZRANGEredis.zrange(key, 0, -1, std::back_inserter(members))输出成员或pair成员,分数ZREMredis.zrem(key, 吕布)long longZCARDredis.zcard(key)long longZCOUNTredis.zcount(key, sw::redis::BoundedIntervaldouble(92, 100, sw::redis::BoundType::CLOSED))long longZPOPMAXauto r redis.zpopmax(key)Optionalpairstring,doubleZPOPMINauto r redis.zpopmin(key)Optionalpairstring,doubleZRANKauto n redis.zrank(key, 吕布)OptionalLongLongZREVRANKauto n redis.zrevrank(key, 吕布)OptionalLongLongZSCOREauto s redis.zscore(key, 吕布)OptionalDoubleZINCRBYredis.zincrby(key, 10, 吕布)doubleZINTERSTOREredis.zinterstore(dest, {key1,key2})long longZUNIONSTOREredis.zunionstore(dest, {key1,key2})long long3.7 示例1. String设置、获取、过期、NXredis.flushdb(); redis.set(mykey, Hello); auto v redis.get(mykey); if (v) printf(%s\n, v-c_str()); // 设置 10 秒过期 redis.set(mykey, Will expire in 10s, std::chrono::seconds(10)); // NX仅当 key 不存在时设置 redis.set(mykey, World, std::chrono::milliseconds(0), sw::redis::UpdateType::NOT_EXIST);2. List批量插入与阻塞弹出redis.rpush(mylist, {one, two, three}); std::vectorstd::string elems; redis.lrange(mylist, 0, -1, std::back_inserter(elems)); auto p redis.blpop({list1, list2}, std::chrono::seconds(5)); if (p) { printf(key%s, value%s\n, p-first.c_str(), p-second.c_str()); }3. Set去重与集合运算redis.sadd(myset, {a, b, c}); std::unordered_setstd::string elements; redis.smembers(myset, std::inserter(elements, elements.begin())); redis.sinterstore(dest, {key1, key2});4. Hash对象字段读写redis.hset(user, name, zhangsan); redis.hset(user, age, 20); auto name redis.hget(user, name); if (name) printf(name%s\n, name-c_str()); std::vectorstd::string fields {name, age}; std::vectorsw::redis::OptionalString values; redis.hmget(user, fields.begin(), fields.end(), std::back_inserter(values));5. Zset排行榜redis.zadd(rank, 吕布, 100); redis.zadd(rank, 赵云, 98); redis.zadd(rank, 典韦, 95); std::vectorstd::pairstd::string, double members; redis.zrange(rank, 0, -1, std::back_inserter(members)); long long n redis.zcount( rank, sw::redis::BoundedIntervaldouble(92, 100, sw::redis::BoundType::CLOSED) );6. 异常处理try { redis.get(mykey); } catch (const sw::redis::ReplyError e) { printf(Redis error: %s\n, e.what()); }4. Optional 返回值必须判断4.1. Optional 返回值redis-plus-plus 中很多命令的返回值不是直接的值而是 sw::redis::OptionalT表示“可能有值也可能没有值”类型典型命令含义OptionalStringget、lpop、rpop、hget、spop字符串可能不存在OptionalLongLongzrank、zrevrank排名可能不存在OptionalDoublezscore分数可能不存在OptionalStringPairblpop、brpop阻塞弹出可能超时无结果auto v redis.get(mykey); auto n redis.zrank(key, 吕布); auto s redis.zscore(key, 吕布); auto p redis.blpop({list1, list2}, std::chrono::seconds(5));这些变量都不能直接当成普通值使用如果 Optional 为空仍然调用 v-c_str()、n.value()、p-first可能导致未定义行为、程序崩溃、抛出异常、数据错乱文档中的正确写法基本都是先判断if (v) { printf(%s\n, v-c_str()); } else { printf((nil)\n); } 或者 if (bool(v)) { printf(%s\n, v-c_str()); } else { printf((nil)\n); }4.2 不同 Optional 类型的判断和取值操作推荐做法判断是否有值if (v)或if (bool(v))取字符串v-c_str()取 long longn.value()取 doublescore.value()取 pairp-first、p-second无值处理输出(nil)或走业务默认逻辑OptionalStringsw::redis::OptionalString v redis.get(mykey); if (v) { printf(value %s\n, v-c_str()); } else { printf((nil)\n); }OptionalLongLongsw::redis::OptionalLongLong n redis.zrank(key, 吕布); if (n) { printf(rank %ld\n, n.value()); } else { printf(member not found\n); }OptionalDoublesw::redis::OptionalDouble score redis.zscore(key, 吕布); if (score) { printf(score %lf\n, score.value()); } else { printf(member not found\n); }OptionalStringPairsw::redis::OptionalStringPair p redis.blpop({list1, list2}, std::chrono::seconds(5)); if (p) { printf(key %s\n, p-first.c_str()); printf(value %s\n, p-second.c_str()); } else { printf((nil)\n); }4.3 关于 value() 和 operator-v-c_str() 等价于通过指针访问内部值前提是 v 有值n.value()、score.value() 也是取值但空 Optional 上调用 value() 可能抛异常生产代码中更推荐先判断再取值5. 批量操作使用迭代器redis-plus-plus 很多批量查询接口不直接返回 vector 或 set而是让你传入一个“输出迭代器”由客户端把结果逐个插入到你指定的容器中这样做的好处不强制绑定容器类型可以输出到 vector、list、set、unordered_set 等接口更通用避免不必要的拷贝和转换命令输出内容推荐容器推荐迭代器keysstringvectorstringstd::back_inserterlrangestringvectorstringstd::back_insertersmembersstringunordered_setstringstd::inserterhmgetOptionalStringvectorOptionalStringstd::back_inserterzrangeOptionalStringvectorOptionalStringstd::back_inserterzrange withscorespairstring,doublevectorpairstring,doublestd::back_inserter5.1 两个核心插入迭代器迭代器作用适用容器要求std::back_inserter尾部插入vector、list、deque容器有push_backstd::inserter指定位置插入set、unordered_set、map容器有insert需要包含头文件 #include iteratorback_inserter 用法适合顺序容器例如 vector、liststd::vectorstd::string keys; redis.keys(*name*, std::back_inserter(keys)); std::vectorstd::string elems; redis.lrange(mylist, 0, -1, std::back_inserter(elems)); std::vectorsw::redis::OptionalString values; std::vectorstd::string fields {name, age}; redis.hmget(key, fields.begin(), fields.end(), std::back_inserter(values)); std::vectorstd::pairstd::string, double members; redis.zrange(key, 0, -1, std::back_inserter(members));inserter 用法适合关联容器例如 set、unordered_setstd::unordered_setstd::string elements; redis.smembers(myset, std::inserter(elements, elements.begin()));unordered_set 没有 push_back所以不能用 back_inserterstd::inserter 的第二个参数是插入位置提示通常传 begin() 即可对于 set、unordered_set重复元素会自动去重