Redis基础:C++操作redis
·
redis系列
文章目录
前言
本文将介绍如何使用编程方式操作Redis。与上篇通过Redis命令行操作不同,实际开发中通常需要通过代码调用Redis API来完成操作。
一、环境准备
1.1、安装 redis-plus-plus
C++ 操作 Redis 有多种库可供选择,其中 redis-plus-plus 是我们的推荐方案。该库功能全面且接口设计简洁易用。
前置依赖:redis-plus-plus 基于 hiredis 开发,需先安装 hiredis
# Ubuntu 系统安装 hiredis
sudo apt install libhiredis-dev
获取 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
1.2、验证redis-plus-plus的功能可用性
#include <iostream>
#include <sw/redis++/redis.h>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
// 创建Redis连接实例,指定服务器地址和端口(需确保IP可达)
sw::redis::Redis redis("tcp://127.0.0.1:6379");
// 测试Redis服务连通性
string result = redis.ping();
cout << result << endl;
return 0;
}

二、C++客户端操作Redis命令
这些命令在上篇文章中已有详细介绍,本文将简单介绍。
2.1、通用命令
2.1.1、get和set命令
void test1(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
//通过set设置key-value
redis.set("key1","111");
redis.set("key2","222");
redis.set("key3","333");
//通过get获取key对应的value
auto value1=redis.get("key1");
if(value1){
cout<<"value1: "<<value1.value()<<endl;
}
auto value2=redis.get("key2");
if(value2){
cout<<"value2: "<<value2.value()<<endl;
}
auto value3=redis.get("key3");
if(value3){
cout<<"value3: "<<value3.value()<<endl;
}
auto value4=redis.get("key4");
if(value4){
cout<<"value4: "<<value4.value()<<endl;
}
}
get函数返回的
sw::redis::OptionalString类型支持隐式转换为布尔值,若不进行判断直接获取value会抛异常

2.1.2、exists/del命令
//exists/del
void test2(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
//通过set设置key-value
redis.set("key1","111");
redis.set("key2","222");
redis.set("key3","333");
//使用exists判断key是否存在
auto ret=redis.exists("key1");
cout<<ret<<endl;
ret=redis.exists("key3");
cout<<ret<<endl;
ret=redis.exists("key4");
cout<<ret<<endl;
//查找多个key
ret=redis.exists({"key1","key2","key3","key4"});
cout<<ret<<endl;
//del删除key
ret=redis.del("key");
cout<<ret<<endl;
ret=redis.del("key1");
cout<<ret<<endl;
ret=redis.del({"key1","key2","key3","key4"});
cout<<ret<<endl;
//验证结果
ret=redis.exists({"key1","key2","key3","key4"});
cout<<ret<<endl;
}

操作结果均显示成功处理了对应数量的键值
2.1.3、keys
//keys
void test3(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
//通过set设置key-value
redis.set("key1","111");
redis.set("key2","222");
redis.set("key3","333");
redis.set("key4","444");
redis.set("key5","555");
redis.set("key6","666");
//keys获取key
vector<string> container;
//这里涉及到了C++插入迭代器,C++部分介绍过了
auto it=std::back_inserter(container);
redis.keys("*",it);
printContainer(container);
}

2.1.4、expire/ttl命令
//expire/ttl
void test4(sw::redis::Redis&redis){
//引入这个可以使用字面长量
using namespace std::chrono_literals;
//清空之前的key
redis.flushdb();
//通过set设置key-value
redis.set("key1","111");
//设置有效时间
//10s字面常量,也可以使用ms
redis.expire("key1",10s);
redis.expire("key1",std::chrono::seconds(10s));
std::this_thread::sleep_for(5s);
//查询有效时间
auto ret=redis.ttl("key1");
cout<<"有效时间:"<<ret<<endl;
std::this_thread::sleep_for(5s);
cout<<redis.exists("key1")<<endl;
}

2.1.5、type命令
//type
void test5(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
redis.set("key1","111");
auto ret=redis.type("key1");
cout<<"key1:"<<ret<<endl;
redis.lpush("key2","222","333");
ret=redis.type("key2");
cout<<"key2:"<<ret<<endl;
redis.hset("key3",{"姓名","张三","年龄","18"});
ret=redis.type("key3");
cout<<"key3:"<<ret<<endl;
redis.sadd("key4",{"唱","跳","rapp"});
ret=redis.type("key4");
cout<<"key4:"<<ret<<endl;
redis.zadd("key5","张三",80);
ret=redis.type("key5");
cout<<"key5:"<<ret<<endl;
ret=redis.ttl("key1");
}

三、常用数据类型命令
3.1、string类型
3.1.1、mset/mget命令
//mget/mset
void test6(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
//借助容器存储
vector<std::pair<string,string>> container{
{"key1","111"},
{"key2","222"},
{"key3","333"}
};
redis.mset(container.begin(),container.end());
//直接存储
redis.mset({std::make_pair("key4","444"),std::make_pair("key5","555")});
//mget
//sw::redis::OptionalString:表示可能有值,可能没值
vector<sw::redis::OptionalString> result;
auto it=std::back_inserter(result);
redis.mget({"key1","key2","key3","key4","key7"},it);
printContainerOptionalString(result);
}

3.1.2、setrange/getrange命令
//setrange/getrange
void test7(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
redis.set("key1","abcdefghigklm");
//获取指定范围数据
string ret=redis.getrange("key1",0,2);
cout<<ret<<endl;
ret=redis.getrange("key1",1,3);
cout<<ret<<endl;
//修改指定范围的数据
redis.setrange("key1",2,"1111");
auto value=redis.get("key1");
cout<<value.value()<<endl;
}

3.1.3、incr/decr命令
//incr/decr
void test8(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
redis.set("key1","100");
//获取指定范围数据
auto ret=redis.incr("key1");
cout<<ret<<endl;
ret=redis.decr("key1");
cout<<ret<<endl;
}

get获取的结果是OptionalString类型,incr/decr返回的则是LongLong类型
3.2、list类型
3.2.1、lpush/lrange命令
void test9(sw::redis::Redis&redis){
//清空之前的key
redis.flushdb();
//插入单个单元
redis.lpush("key1","111");
//插入一组数据,基于初始化列表
redis.lpush("key1",{"222","333","444","555"});
//插入一组数据,基于迭代器
vector<string> container={
"666",
"777",
"888"
};
redis.lpush("key1",container.begin(),container.end());
//获取指定范围的元素
vector<string> values;
auto it=std::back_inserter(values);
redis.lrange("key1",0,-1,it);
printContainer(values);
}

3.2.3、blpop命令

using OptionalStringPair = std::optional<std::pair<std::string, std::string>>
BLPOP 函数支持同时操作多个键,因此返回结果采用键值对形式:first 字段标识被删除值所属的列表,second 字段记录被删除的具体值。
void test10(sw::redis::Redis&redis){
using namespace std::chrono_literals;
//清空之前的key
redis.flushdb();
auto ret=redis.blpop({"key1","key2","key3"},10s);//阻塞十秒,若不显示设置,则一直阻塞
if(ret){
cout<<"key:"<<ret.value().first<<endl;
cout<<"value:"<<ret.value().second<<endl;
}else{
cout<<"list为空"<<endl;
}
}

3.3、set类型
3.3.1、sadd/smembers命令
// sadd/smembers 操作测试
void test11(sw::redis::Redis& redis) {
using namespace std::chrono_literals;
// 清空数据库
redis.flushdb();
// 单值插入
redis.sadd("key1", "111");
// 通过初始化列表插入多个值
redis.sadd("key1", {"222", "333", "444"});
// 通过容器插入多个值
vector<string> elems = {"555", "666", "777"};
redis.sadd("key1", elems.begin(), elems.end());
set<string> container;
// 使用插入迭代器获取集合成员
auto it = std::insert_iterator(container, container.end());
redis.smembers("key1", it);
printContainer(container);
}

3.3.2、sismember/spop/scard命令
//sismember/spop/scard命令
void test12(sw::redis::Redis&redis){
using namespace std::chrono_literals;
//清空之前的key
redis.flushdb();
//单键插入
redis.sadd("key1","111");
//插入一组数据,基于初始换列表
redis.sadd("key1",{"222","333","444"});
//插入一组数据,基于容器插入
vector<string> elems{
"555",
"666",
"777"
};
//判断元素是否存在于set中
bool ret=redis.sismember("key1","111");
cout<<ret<<endl;
//对获取set中member的数量
auto res=redis.scard("key1");
cout<<res<<endl;
//随机删除元素
auto result=redis.spop("key1");
cout<<result.value()<<endl;
}

3.3.3、sinter/sinterstore命令
void test13(sw::redis::Redis& redis) {
redis.flushall();
redis.sadd("key1", {"111", "222", "333"});
redis.sadd("key2", {"111", "222", "444"});
set<string> result;
auto it = std::inserter(result, result.end());
redis.sinter({"key1", "key2"}, it);
printContainer(result);
result.clear();
cout<<"-------------------------------"<<endl;
std::cout << "sinterstore" << std::endl;
long long len = redis.sinterstore("key3", {"key1", "key2"});
std::cout << "len: " << len << std::endl;
redis.smembers("key3", it);
printContainer(result);
}

3.3.4、hset/hget命令
void test14(sw::redis::Redis& redis) {
std::cout << "hset 和 hget" << std::endl;
redis.flushall();
// 方式1:单字段设置
redis.hset("key", "f1", "111");
// 方式2:使用 pair 设置单字段
redis.hset("key", std::make_pair("f2", "222"));
// 方式3:一次性插入多个 field-value 对(初始化列表)
redis.hset("key", {
std::make_pair("f3", "333"),
std::make_pair("f4", "444")
});
// 方式4:使用迭代器批量插入
vector<std::pair<string, string>> fields = {
std::make_pair("f5", "555"),
std::make_pair("f6", "666")
};
redis.hset("key", fields.begin(), fields.end());
// 获取字段值
auto result = redis.hget("key", "f3");
if (result) {
std::cout << "result: " << result.value() << std::endl;
} else {
std::cout << "result 无效!" << std::endl;
}
}

3.3.5、hexists/hdel命令
void test15(sw::redis::Redis& redis) {
std::cout << "hexists" << std::endl;
redis.flushall();
redis.hset("key", "f1", "111");
redis.hset("key", "f2", "222");
redis.hset("key", "f3", "333");
// 判断字段 "f4" 是否存在
bool result = redis.hexists("key", "f4");
std::cout << "result: " << result << std::endl;
cout<<"----------------------------"<<endl;
std::cout << "hdel" << std::endl;
// 删除单个字段 "f1"
long long ret = redis.hdel("key", "f1");
std::cout << "ret: " << ret << std::endl;
// 批量删除字段 "f2" 和 "f3"
ret = redis.hdel("key", {"f2", "f3"});
std::cout << "ret: " << ret << std::endl;
// 获取哈希表中剩余的字段数量
long long len = redis.hlen("key");
std::cout << "len: " << len << std::endl;
}

3.3.6、hkeys/hvals命令
void test16(sw::redis::Redis& redis) {
std::cout << "hkeys 和 hvals" << std::endl;
redis.flushall();
// 插入哈希字段
redis.hset("key", "f1", "111");
redis.hset("key", "f2", "222");
redis.hset("key", "f3", "333");
// 获取所有字段名(hkeys)
vector<string> fields;
auto itFields = std::back_inserter(fields);
redis.hkeys("key", itFields);
printContainer(fields);
// 获取所有字段值(hvals)
vector<string> values;
auto itValues = std::back_inserter(values);
redis.hvals("key", itValues);
printContainer(values);
}

3.4、zset类型
3.4.1 zadd/zrange命令
void test16(sw::redis::Redis& redis) {
redis.flushall();
// 1. 单条插入
redis.zadd("key", "吕布", 99);
// 2. 初始化列表批量插入
redis.zadd("key", {
std::make_pair("赵云", 98),
std::make_pair("典韦", 97)
});
// 3. vector 迭代器方式插入
// 注意:zadd 要求分数是 double 类型,必须用 pair<string, double>
vector<std::pair<string, double>> members = {
std::make_pair("关羽", 95),
std::make_pair("张飞", 93),
};
redis.zadd("key", members.begin(), members.end());
// zrange 支持两种主要的风格:
// 1. 只查询 member, 不带 score
// 2. 查询 member 同时带 score
// 关键就是看插入迭代器指向的容器的类型.
// 指向的容器只是包含一个 string, 就是只查询 member
// 指向的容器包含的是一个 pair, 里面有 string 和 double, 就是查询 member 同时带有 score
// 第一种:只获取成员名称
vector<string> memberResults;
auto it = std::back_inserter(memberResults);
redis.zrange("key", 0, -1, it);
printContainer(memberResults);
// 第二种:同时获取成员名称 + 分数
vector<std::pair<string, double>> membersWithScore;
auto it2 = std::back_inserter(membersWithScore);
redis.zrange("key", 0, -1, it2);
printContainerPair(membersWithScore);
}

更多推荐
所有评论(0)