当前位置: 首页 > news >正文

初识Redis · C++客户端string

目录

前言:

string的API使用

set get:

expire:

NX XX:

mset,mget:

getrange setrange:

incr decr


前言:

在前文,我们已经学习了Redis的定制化客户端怎么来的,以及如何配置好Redis定制化客户端,并且简单学习了一下RESP,其实也就是了解了一下为什么Redis可以定制化客户端而已,那么,我们现在有了Redis定制化客户端的条件,我们自然就可以使用大佬们封装好的Redis的API了。

那么在本文呢,我们涉及到的是string,list和hash的多组API,因为我们是在命令行敲过的,所以学习起来也是非常快的了。

废话不多说,进入主题吧!


string的API使用

对于string的API使用,我们大致分为了 set get expire mset mget getrange setrange incr decr,大致就这么多命令,因为其他命令其实也大差不差,我们就使用过这些也都清楚了。

set get

我们创建好了redis对象之后,啥也不管,直接set,我们可以看到它的参数还是挺多的,但是当我们一看,第一个参数是key,第二个参数是val,第三个参数是chrno的时间,这不就是存活时间吗,第四个参数是一些设置,比如NX,XX等。

这样一看是非常清楚的了。

但是我们发现set的参数是Stringview类型的,这个类型和string类型来说最大的区别就是这个类型是只读的,我们可以通过阅读源码简单了解:

      begin() const noexcept{ return this->_M_str; }constexpr const_iteratorend() const noexcept{ return this->_M_str + this->_M_len; }constexpr const_iteratorcbegin() const noexcept{ return this->_M_str; }constexpr const_iteratorcend() const noexcept{ return this->_M_str + this->_M_len; }

这里是它经过重重封装后的源码,我们可以发现它的迭代器都是const类型,也就是不允许我们修改*this了,它即只读的

因为是只读的,所以针对只读的这个操作做了很多优化,效率就比普通的std::string快了。当然了,在C++17中,标准库也提供了std::string_view,操作和string类似,只是包括了一些只读的方法。

那么我们既然set了,我们肯定要get,我们先看看get的返回值:

通过返回值和备注,我们看到了它的返回值是OptionalString,如果key是不存在的,那么会返回的就是通过nullop构造的OptionalString对象。那么OptionalString是什么呢~

实际上,它的出现是因为为了更好的处理key不存在的这个情况,在我们学习命令行的时候,我们如果使用get查看一个不存在的key,返回值是nil,也就是空的意思,那么如果它的返回值是string,我们如何表达nil

如果返回空串,我们并不排除key对应的value就是空串,如果我们再复杂一点,返回一个string*,指向的是空就代表nil,可是这样又会引发出内存安全的问题。

所以,Redis官方给出的操作是给了一个类型:OptionalString,主要是为了处理nil的情况。

但是作为C++学习者我们不能不知道boost在C++14的时候就已经引入了optional<std::string>的概念了,后来在C++17的时候我们直接就包含optional的头文件就行了。

我们先来看一段正确的使用:

void test_1(Redis& redis)
{redis.flushall();redis.set("key","111");auto value = redis.get("key");if(value)std::cout << value.value() << std::endl;else std::cout << "值不存在" << std::endl;}

我们一共发现了三处左右较为陌生的点,一个是我们使用auto来接收,一个是我们用if来判断value,一个是我们使用的value.value()打印。

首先,我们最能够理解的点是,<<运算符并不支持OptionalString的打印,所以我们需要通过value()方法来返回string类型,其实我们也能通过*value来解决,它们的返回值都是string,*是重载了解引用操作符,.value()就是显示的调用了对应的成员函数。

  if(value)std::cout << *value << std::endl;else std::cout << "值不存在" << std::endl;

其次,我们还能理解的是,如果我们get的是一个不存在的键值,那么OptionalString返回值就是类似于nil的结果,所以我们最好是做一个类型检查。

最后,我们使用auto来接收,其实我们使用optional<string>接收也不是不行,但是为了方便嘛,我们可以直接使用auto接收。不过就需要你包含对应的头文件了。

对应value()方法有一个特点就是如果key不存在,就会抛异常,像这样

从上面这个代码的例子,我们认识了OptionalStringstringView

那么为了测试方便,我们最好在对Redis进行操作的时候flushall一下,以下是第一个测试的代码:

void test_1(Redis &redis)
{redis.flushall();redis.set("key", "111");auto value = redis.get("key");// std::optional<std::string> value = redis.get("key");// if(value)//     std::cout << *value << std::endl;// else//     std::cout << "值不存在" << std::endl;std::cout << value.value() << std::endl;
}
int main()
{Redis redis("tcp://127.0.0.1:6379");test_1(redis);return 0;
}

expire:

然后我们来测试以下超时时间,在set的构造函数中,我们直接加就可以了:

void test_2(Redis &redis)
{redis.flushall();redis.set("key","111",std::chrono::seconds(10));using namespace std::chrono_literals;redis.set("key1","222",10s);std::this_thread::sleep_for(3s);long long time = redis.ttl("key");std::cout << "剩余时间为:" << time << std::endl;}

这里的代码就比较简单了,第一个点是设置过期时间有两种方式,一种是使用命令空间chrono的seconds函数或者millonseconds函数,第二种方式是我们引入命名空间chrono_literals,这样我们就可以直接使用字面值常量了。

然后我们就正常根据ttl的返回值,来接收以下time就可以了:

至于为什么使用chrono等,因为C++不像py可以直接传10表示时间,C++没有内置时间单位,所以需要一个库专门用来表示时间的,就像上面的两个。

NX XX:

接着我们来测试NX和XX:

一般默认的是ALWAYS,XX对应的是EXIST,NX对应的是NOT_EXIST:

void test_3(Redis &redis)
{redis.flushall();redis.set("key", "111", 0s,sw::redis::UpdateType::NOT_EXIST);auto value = redis.get("key");if(value)std::cout << value.value() << std::endl;else   std::cout << "not exist"<< std::endl;
}

mset,mget

对于mset和mget来说就是今天的难点了算是,当然仅仅相对而言,它不过是需要我们引入迭代器的概念而已。

由于传键值对的时候,get和mget的键值对都是pair类型的,所以我们使用mget的时候,官方给我们提供了两个角度,一个是使用initailizer_list,一个是使用容器的迭代器

void test_4(Redis &redis)
{redis.flushall();// redis.mset({"key1","111","key2","222"}); // errorredis.mset({std::make_pair("key","111"),std::make_pair("key1","222")});std::vector<std::pair<std::string, std::string>> vec{std::make_pair("key2","222"),std::make_pair("key3","333")};std::vector<std::pair<std::string, std::string>> vec2{{"key4","444"},{"key5","555"}};redis.mset(vec.begin(), vec.end());redis.mset(vec2.begin(), vec2.end());std::vector<std::string> result;auto iter = std::back_inserter(result); redis.mget({"key","key2","key4"},iter);for(auto ele:result){std::cout << ele << ' ';}std::cout << std::endl;
}

对于mset和mget来说,较为特殊,使用mset的时候,我们有两种方式,一种,我们可以直接使用initailizer_list初始化,就像构建key 和 key1的时候,我们也可以通过重载迭代器的方式,即我们先定义一个容器,可以是list可以是set可以是Vector,构造好了之后,mset直接传入两个的迭代器的就可以了。

然后是mget,使用mget的时候,我们可以看看参数:

它的第二个参数是back_insert_iterator,其实就是尾插迭代器,在STL中,迭代器分为了五种类型,分别是输入迭代器,输出迭代器,前向迭代器,双向迭代器和随机访问迭代器,其中对于back_inserter来说,它就是输出迭代器的一种,mget获取到value之后,就把输出给到这个迭代器对应的容器里面。

那么给的方式,就是看位置了,比如back_inserter对应的位置是尾,那么就相当于给这个容器一直尾插。

它们对应了不同的迭代器,比如back_insert_iterator,insert_iterator,但是我们一般不会直接构造出这几个对象,我们一般会走一些辅助的函数来构造,比如back_inserter。

getrange setrange:

这两个我们如果有了C++string函数的理解,那就非常简单了,无非是我们要确定位置,给个偏移量,然后给上对应的字符串就可以了。

void test_5(Redis &redis)
{redis.flushall();redis.set("key","abcdefghijk");redis.setrange("key",2,"11111111");std::string result = redis.getrange("key",2,-1);std::cout << result << std::endl;
}

incr decr

同理,非常简单,我们直接给代码:

void test_6(Redis &redis)
{redis.flushall();redis.set("key", "20");redis.incr("key");auto value = redis.get("key");if (value)std::cout << value.value() << std::endl;redis.decr("key");value = redis.get("key");if (value)std::cout << value.value() << std::endl;
}

也是非常简单了。

其实文本篇幅较多仅是因为第一次使用Redis对应的API,那么在之后介绍list和hash的时候节奏就会快了。

本文的难点是在mset和mget的时候,如何正确使用迭代器的问题,其他难度相对来说是比较低的。


感谢阅读!

相关文章:

  • 先导木工机床与养老领域的探索之旅
  • 仿腾讯会议项目实现——设置配置文件
  • 【特殊场景应对1】视觉设计:信息密度与美学的博弈——让简历在HR视网膜上蹦迪的科学指南
  • 6.7.图的深度优先遍历(英文缩写DFS)
  • EnlightenGAN:低照度图像增强
  • 【计算机网络 | 第一篇】计算机网络基础知识
  • 基于springBoot+vue的PC 端学习系统(源码+lw+部署文档+讲解),源码可白嫖!
  • L2-018 多项式A除以B
  • 电脑 BIOS 操作指南(Computer BIOS Operation Guide)
  • 累计达2.04亿户!中国联通首次公布5G网络用户数据
  • 使用MetaGPT 创建智能体(2)多智能体
  • 创维E900V20C-国科GK6323V100C-rtl8822cs-安卓9.0-短接强刷卡刷固件包
  • 遥感技术赋能电力设施监控:应用案例篇
  • 链表相关算法题
  • git clean password
  • Vue2+Vue3 130~180集学习笔记
  • OpenHarmony-Risc-V上运行openBLAS中的benchmark
  • C++ 迭代器失效详解:如何避免 vector 操作中的陷阱
  • SQL预编译——预编译真的能完美防御SQL注入吗
  • C#插件与可扩展性
  • 2025中国互联网企业家座谈会在京召开
  • “站在亚洲实现整体振兴的新起点上”——习近平主席对越南、马来西亚、柬埔寨进行国事访问纪实
  • 儿童阅读空间、残疾人友好书店……上海黄浦如何打造城市书房
  • 对话地铁读书人|来自法学副教授的科普:读书日也是版权日
  • 非法收受财物2.29亿余元,窦万贵受贿案一审开庭
  • 日本多地发生无差别杀人事件,中使馆提醒中国公民加强安全防范