[Redis][C++客户端]详细讲解

ops/2024/10/17 21:58:52/

目录

  • 0.RESP
  • 1.前置依赖 -- hiredis
  • 2.安装 redis-plus-plus
  • 3.示例:通用命令
    • 1.Quick Start
    • 2.Get && Set
    • 3.Exists
    • 4.Keys
    • 5.Expire && TTL
    • 6.Type
  • 4.示例:String
    • 1.Set with expire
    • 2.Set NX / XX
    • 3.Mset
    • 4.Mget
    • 5.Getrange && Setrange
  • 5.示例:list
    • 1.Push && Range
    • 2.Pop
    • 3.blpop
    • 4.llen
  • 6.示例:set
    • 1.Sadd && Smembers
    • 2.Sismerber
    • 3.Scard
    • 4.Spop
    • 5.Sinter
    • 6.Sinterstore
  • 7.示例:hash
    • 1.Hset && Hget
    • 2.Hexists
    • 3.Hdel
    • 4.Hkeys && Hvals
    • 5.Hmget && Hmset
  • 8.示例:zset
    • 1.Zadd && Zrange
    • 2.Zcard
    • 3.Zrem
    • 4.Zscore

RESP_1">0.RESP

  • RESP:Redis自定义的应用层协议
    • 传输层基于TCP,但是和TCP又没有强耦合
  • 优点
    • 简单好实现
    • 快速进行解析
    • 肉眼可读
  • 工作流程:请求和响应之间的通信模型是一问一答的形式
    • 客户端给服务器发一个请求(Redis 命令),服务器返回一个响应
    • 客户端和服务器只需要按照格式,构造出字符串,往socket中写入或者从socket中读取字符串,按照上述格式解析

redis_14">1.前置依赖 – hiredis

  • redis-plus-plus 是基于hiredis实现的,hiredis是⼀个C语⾔实现的Redis客⼾端
  • 安装apt install libhiredis-dev

redisplusplus_20">2.安装 redis-plus-plus

  • C++操作Redis的库有很多,此处使用redis-plus-plus,该库功能强大,使用简单,
    • Github、详细API
  • 安装
    git clone https://github.com/sewenew/redis-plus-plus.gitcd redis-plus-plus
    mkdir build && cd buildcmake .. -DCMAKE_INSTALL_PREFIX=/usr
    make
    make install
    
  • 说明redis-plus-plus该库接口风格非常统一,用起来非常舒服
    • 当一个函数,参数需要传递多个值的时候,往往都是支持初始化列表或者是一对迭代器的方式,来进行实现
    • 当一个函数,返回值需要表示多个数据的时候,也往往会接入插入迭代器,来实现往一个容器中添加元素的效果
    • 当某些场景涉及到无效值的时候,往往会搭配std::optional来进行使用

3.示例:通用命令

1.Quick Start

  • main.cc
    #include <iostream>
    #include <string>
    #include <sw/redis++/redis++.h>
    using namespace std;int main()
    {// 构建Redis对象的时候,在构造函数中,指定Redis服务器的地址和端口sw::redis::Redis redis("tcp://127.0.0.1:6379");string ret = redis.ping();cout << ret << endl;return 0;
    }
    
  • Makefile
    main:main.ccg++ -std=c++17 -o $@ $^ -l redis++ -l hiredis -l pthread.PHONY:clean
    clean:rm main
    

2.Get && Set

  • 此处的redis.get()返回的是一个optional类型
    • optional类型在C++14中,正式纳入标准库
    • 因为redis.get()会返回nil无效值,用std::string不方便表现nil,而std::string*虽然可以用nullptr表示无效,但是返回指针又设计内存管理问题
    • 所以综上,此处使用optional表示"非法值"/“无效值”
    void TestGetAndSet(sw::redis::Redis& redis)
    {// 清空数据库,避免之前残留的数据干扰redis.flushall();// 使用set设置keyredis.set("key1", "233");redis.set("key2", "666");redis.set("key3", "888");// 使用get获取到key对应的valueauto value1 = redis.get("key1");// optional 可以隐式转成 bool 类型, 可以直接在 if 中判定. 如果是无效元素, 就是返回 falseif(value1){cout << "value1=" << value1.value() << endl; // sw::redis::OptionalString没有重载<<}auto value2 = redis.get("key2");if(value2){cout << "value2=" << value2.value() << endl;}auto value3 = redis.get("key3");if (value2){cout << "value3=" << value3.value() << endl;}auto value4 = redis.get("key4");if (value4){// 如果不加判断,则会在此处抛出异常 std::bad_optional_acesscout << "value4=" << value4.value() << endl;}
    }
    

3.Exists

void TestExists(sw::redis::Redis &redis)
{redis.flushall();redis.set("key1", "111");redis.set("key3", "111");auto ret = redis.exists("key1");cout << ret << endl;ret = redis.exists("key2");cout << ret << endl;// exists()的重载形式,可以用一个初始化列表传参ret = redis.exists({"key1", "key2", "key3"});cout << ret << endl;
}

4.Keys

void TestKeys(sw::redis::Redis &redis)
{redis.flushall();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 的第二个参数, 是一个 "插入迭代器". 需要先准备好一个保存结果的容器.// 接下来再创建一个插入迭代器指向容器的位置. 就可以把 keys 获取到的结果依次通过刚才的插入迭代器插入到容器的指定位置中了.// 插入迭代器 -> 位置 + 动作vector<string> ret;auto it = std::back_inserter(ret);redis.keys("*", it);PrintContainer(ret);
}

5.Expire && TTL

void TestExpireAndTTL(sw::redis::Redis &redis)
{redis.flushall();redis.set("key", "111");// 10s -> std::chrono::seconds(10);redis.expire("key", 10s); // 此处10s为字面值,类似于2.33fstd::this_thread::sleep_for(3s);auto time = redis.ttl("key");cout << time << endl;
}

6.Type

void TestType(sw::redis::Redis& redis)
{redis.flushall();redis.set("key1", "111");string result = redis.type("key");cout << "key1: " << result << endl;redis.lpush("key2", "111");result = redis.type("key2");cout << "key2: " << result << endl;redis.hset("key3", "aaa", "111");result = redis.type("key3");cout << "key3: " << result << endl;redis.sadd("key4", "aaa");result = redis.type("key4");cout << "key4: " << result << endl;redis.zadd("key5", "吕布", 99);result = redis.type("key5");cout << "key5: " << result << endl;
}

4.示例:String

1.Set with expire

void TestSetWithExpire(Redis& redis)
{redis.flushall();redis.set("key", "111", 10s);std::this_thread::sleep_for(3s);long long time = redis.ttl("key");std::cout << "time: " << time << std::endl;
}

2.Set NX / XX

void TestSetNXAndXX(Redis &redis)
{redis.flushall();redis.set("key", "111");// set 的重载版本中, 没有单独提供 NX 和 XX 的版本, 必须搭配过期时间的版本来使用// 过期时间填0s则为永不过期redis.set("key", "222", 0s, sw::redis::UpdateType::EXIST); auto value = redis.get("key");if (value){std::cout << "value: " << value.value() << std::endl;}
}

3.Mset

void TestMset(Redis &redis)
{redis.flushall();// 第一种写法, 使用初始化列表描述多个键值对// redis.mset({ std::make_pair("key1", "111"), std::make_pair("key2", "222"), std::make_pair("key3", "333") });// 第二种写法, 可以把多个键值对提前组织到容器中. 以迭代器的形式告诉 msetvector<pair<string, string>> keys = {{"key1", "111"},{"key2", "222"},{"key3", "333"}};redis.mset(keys.begin(), keys.end());auto value = redis.get("key1");if (value){std::cout << "value: " << value.value() << std::endl;}value = redis.get("key2");if (value){std::cout << "value: " << value.value() << std::endl;}value = redis.get("key3");if (value){std::cout << "value: " << value.value() << std::endl;}
}

4.Mget

void TestMget(Redis &redis)
{redis.flushall();vector<std::pair<string, string>> keys = {{"key1", "111"},{"key2", "222"},{"key3", "333"}};redis.mset(keys.begin(), keys.end());vector<sw::redis::OptionalString> result;auto it = std::back_inserter(result);redis.mget({"key1", "key2", "key3", "key4"}, it);PrintContainerOptional(result);
}

5.Getrange && Setrange

void TestRange(Redis &redis)
{redis.flushall();redis.set("key", "DieKSnowK");string result = redis.getrange("key", 2, 5);cout << "result: " << result << endl;redis.setrange("key", 2, "xyz");auto value = redis.get("key");cout << "value: " << value.value() << endl;
}

5.示例:list

1.Push && Range

void TestPushAndRange(Redis &redis)
{redis.flushall();// 插入单个元素redis.lpush("key", "111");// 插入一组元素, 基于初始化列表redis.lpush("key", {"222", "333", "444"});// 插入一组元素, 基于迭代器vector<string> values = {"555", "666", "777"};redis.lpush("key", values.begin(), values.end());// lrange 获取到列表中的元素vector<string> results;auto it = std::back_inserter(results);redis.lrange("key", 0, -1, it);PrintContainer(results);
}

2.Pop

void TestPop(Redis &redis)
{redis.flushall();// 构造一个 listredis.rpush("key", {"1", "2", "3", "4"});auto result = redis.lpop("key");if (result){std::cout << "lpop: " << result.value() << std::endl;}result = redis.rpop("key");if (result){std::cout << "rpop: " << result.value() << std::endl;}
}

3.blpop

  • TIPS:对于std::optional类型来说,可以直接使用->访问optional内部包含的元素的成员
    void TestBlpop(Redis &redis)
    {redis.flushall();auto result = redis.blpop({"key", "key2", "key3"}, 10s);// 此处可以考虑在其他redis-cli插入数据以便进一步观察效果if (result){std::cout << "key:" << result->first << std::endl;std::cout << "elem:" << result->second << std::endl;}else{std::cout << "result 无效!" << std::endl;}
    }
    

4.llen

void TestLlen(Redis &redis)
{redis.flushall();redis.lpush("key", {"111", "222", "333", "444"});long long len = redis.llen("key");cout << "len: " << len << endl;
}

6.示例:set

1.Sadd && Smembers

  • 此处要注意保存结果的方式和之前的区别
    void TestSaddAndSmembers(Redis& redis)
    {redis.flushall();// 一次添加一个元素redis.sadd("key", "111");// 一次添加多个元素(使用初始化列表)redis.sadd("key", {"222", "333", "444"});// 一次添加多个元素(使用迭代器)set<string> elems = {"555", "666", "777"};redis.sadd("key", elems.begin(), elems.end());// 获取到上述元素// vector<string> result;// auto it = std::back_inserter(result);// 此处用来保存 smembers 的结果, 使用 set 可能更合适.set<string> result;// 由于此处 set 里的元素顺序是固定的. 指定一个 result.end() 或者 result.begin() 或者其他位置的迭代器, 都无所谓auto it = std::inserter(result, result.end());redis.smembers("key", it);PrintContainer(result);
    }
    

2.Sismerber

void TestSismember(Redis& redis)
{redis.flushall();redis.sadd("key", {"111", "222", "333", "444"});bool result = redis.sismember("key", "555");cout << "result: " << result << endl;
}

3.Scard

void TestScard(Redis &redis)
{redis.flushall();redis.sadd("key", {"111", "222", "333"});long long result = redis.scard("key");cout << "result: " << result << endl;
}

4.Spop

void TestSpop(Redis& redis)
{redis.flushall();redis.sadd("key", {"111", "222", "333", "444"});auto result = redis.spop("key");if (result){std::cout << "result: " << result.value() << std::endl;}else{std::cout << "result 无效!" << std::endl;}
}

5.Sinter

void TestSinter(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);
}

6.Sinterstore

void TestSinterstore(Redis &redis)
{redis.flushall();redis.sadd("key1", {"111", "222", "333"});redis.sadd("key2", {"111", "222", "444"});long long len = redis.sinterstore("key3", {"key1", "key2"});cout << "len: " << len << endl;set<string> result;auto it = std::inserter(result, result.end());redis.smembers("key3", it);PrintContainer(result);
}

7.示例:hash

1.Hset && Hget

void TestHsetAndHget(Redis &redis)
{redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", std::make_pair("f2", "222"));// hset 能够一次性插入多个 field-value 对redis.hset("key", {std::make_pair("f3", "333"),std::make_pair("f4", "444")});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;}
}

2.Hexists

void TestHexists(Redis &redis)
{redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");bool result = redis.hexists("key", "f4");std::cout << "result: " << result << std::endl;
}

3.Hdel

void TestHdel(Redis &redis)
{redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");long long result = redis.hdel("key", "f1");std::cout << "result: " << result << std::endl;result = redis.hdel("key", {"f2", "f3"});std::cout << "result: " << result << std::endl;long long len = redis.hlen("key");std::cout << "len: " << len << std::endl;
}

4.Hkeys && Hvals

void TestHkeysAndHvals(Redis &redis)
{redis.flushall();redis.hset("key", "f1", "111");redis.hset("key", "f2", "222");redis.hset("key", "f3", "333");vector<string> fields;auto itFields = std::back_inserter(fields);redis.hkeys("key", itFields);PrintContainer(fields);vector<string> values;auto itValues = std::back_inserter(values);redis.hvals("key", itValues);PrintContainer(values);
}

5.Hmget && Hmset

void TestHmgetAndHmset(Redis &redis)
{redis.flushall();redis.hmset("key", {std::make_pair("f1", "111"),std::make_pair("f2", "222"),std::make_pair("f3", "333")});vector<std::pair<string, string>> pairs = {std::make_pair("f4", "444"),std::make_pair("f5", "555"),std::make_pair("f6", "666")};redis.hmset("key", pairs.begin(), pairs.end());vector<string> values;auto it = std::back_inserter(values);redis.hmget("key", {"f1", "f2", "f3"}, it);PrintContainer(values);
}

8.示例:zset

1.Zadd && Zrange

  • zrange支持两种主要的风格:
    • 只查询member, 不带score
    • 查询member同时带score
  • 关键就是看插入迭代器指向的容器的类型
    • 指向的容器只是包含一个string, 就是只查询member
    • 指向的容器包含的是一个pair, 里面有stringdouble, 就是查询member同时带有score
    void TestZaddAndZrange(Redis &redis)
    {redis.flushall();redis.zadd("key", "吕布", 99);redis.zadd("key", {std::make_pair("赵云", 98),std::make_pair("典韦", 97)});vector<std::pair<string, double>> members = {std::make_pair("关羽", 95),std::make_pair("张飞", 93)};redis.zadd("key", members.begin(), members.end());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);
    }
    

2.Zcard

void TestZcard(Redis &redis)
{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: " << result << std::endl;
}

3.Zrem

void TestZrem(Redis &redis)
{redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);redis.zrem("key", "zhangsan");long long result = redis.zcard("key");std::cout << "result: " << result << std::endl;
}

4.Zscore

void TestZscore(Redis &redis)
{redis.flushall();redis.zadd("key", "zhangsan", 90);redis.zadd("key", "lisi", 91);redis.zadd("key", "wangwu", 92);redis.zadd("key", "zhaoliu", 93);auto score = redis.zscore("key", "zhangsan");if (score){std::cout << "score: " << score.value() << std::endl;}else{std::cout << "score 无效" << std::endl;}
}


http://www.ppmy.cn/ops/119204.html

相关文章

JS网页设计案例

下面是一个简单的 JavaScript 网页设计案例&#xff0c;展示了如何使用 HTML、CSS 和 JavaScript 创建一个动态的网页。 案例&#xff1a;简单的待办事项列表 1. HTML 部分 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8…

phpstudy简易使用

注意&#xff0c;本文所述的操作步骤均建立在电脑上已经完成php环境变量的配置与vscode的安装之上 、

【算法系列-数组】二分查找

【算法系列-数组】二分查找 文章目录 【算法系列-数组】二分查找1. 算法分析2. 搜索插入位置(LeetCode 35)2.1 解题思路2.2 解题过程2.3 代码 3. 在排序数组中查找元素的第一个和最后一个位置(LeetCode 34)3.1 解题思路3.2 解题过程3.3 代码 4. X的平方根(LeetCode 69)4.1 解题…

testRigor测试用例模板记录

testRigor测试用例模板记录 Application Description Template Application Name Name: MySampleAppApplication Type Type: Web Application / Mobile Application / Desktop ApplicationFunctionality Overview Description: MySampleApp is an online shopping platform t…

【计算机网络】网络层详解

文章目录 一、引言二、IP 基础知识1、IP 地址2、路由3、IP报文4、IP报文的分片与重组 三、IP 属于面向无连接型四、IP协议相关技术1、DNS2、ICMP3、NAT技术4、DHCP 一、引言 TCP/IP的心脏是网络层。这一层主要由 IP 和 ICMP 两个协议组成。网络层的主要作用是“实现终端节点之…

【C++打怪之路Lv4】-- 类和对象(中)

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…

ECharts设置xAxis轴的name位置

x轴的name默认是显示在x轴的最后面&#xff0c;但是需求要把name 显示在x轴的上方&#xff0c;所以需要设置nameTextStyle&#xff0c;设置行高&#xff0c;padding和verticalAlign xAxis: { type: value, name: 个, nameTextStyle: { lineHeight: 30, //标题…

第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)

梁哲&#xff0c;同济大学长聘特聘教授&#xff0c;国家杰青、首届国家杰青延续项目获得者、上海市曙光学者、上海市优秀学术带头人。本科毕业于新加坡国立大计算机工程系、硕士毕业于新加坡国立大学工业与系统工程系、博士毕业于美国新泽西州立大学工业工程系。理论研究主要集…