Redis:cpp.redis++通用接口

Redis:cpp.redis++通用接口


本博客讲解redisC++客户端redis-plus-plus,这个版本的客户端,接口和redis原生命令几乎完全一致,博客内部不会详细讲解每个接口的具体功能,因为和redis命令是一样的,而是重点讲解器用法与参数。所有接口可以参考文档:[redis-plus-plus/redis.h]。

redis对象

redis的所有操作都基于一个redis对象。

C++文件中写入以下代码:

bash 复制代码
#include <iostream>
#include <sw/redis++/redis++.h>

int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    std::string result = redis.ping();
    std::cout << result << std::endl;

    return 0;
}

在默认的路径下,redis++.h头文件放在了sw/redis++/目录下,其中sw是库作者的名称缩写。

main函数中,先创建一个Redis对象,其包含在命名空间sw::redis::内部。在创建对象时,要制定ip和端口号,格式如下:

cpp 复制代码
tcp://IP地址:端口

其中redis的默认端口为6379

redis可以使用ping来检测连通性,通过redis.ping(),会返回一个字符串。

随后对代码进行编译:

cpp 复制代码
g++ -o test_redis test.cpp -std=c++17 -l hiredis -l redis++ -l pthread

redis++需要依赖三个库:hiredisredis++pthread

如果运行程序,输出了PONG,那么说明redis是正常可用的。


通用接口

set & get

  • set函数声明如下:
cpp 复制代码
bool set(const StringView &key,
            const StringView &val,
            const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
            UpdateType type = UpdateType::ALWAYS);

此处有一个StringView类型,是一个只读的字符串,其效率比std::string更高,不过在C++17中也支持了std::string_view。只需要把它当作一般的std::string也没什么大问题。

函数中,前两位是keyvalue其余的都是缺省参数,所以可以只输入keyvalue

  • get函数声明如下:
cpp 复制代码
OptionalString get(const StringView &key);

get的返回值也很特别,是一个OptionalString类型,这是因为redis中如果查询为空,会返回nil,对于std::string不好表示这样的空,所以使用了OptionalString来处理,一般用auto接收即可。

要注意的是OptionalString不支持operator<<,要通过.value()函数,获取其内部包含的std::string即可。

示例:

cpp 复制代码
#include <iostream>
#include <sw/redis++/redis++.h>

int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");

    redis.set("key1", "111");
    redis.set("key2", "222");

    auto ret1 = redis.get("key1");
    std::cout << ret1.value() << std::endl;

    auto ret2 = redis.get("key2");
    std::cout << ret2.value() << std::endl;
    
    auto ret3 = redis.get("key3");
    std::cout << ret3.value() << std::endl;

    return 0;
}

输出结果:

cpp 复制代码
111
222
terminate called after throwing an instance of 'std::bad_optional_access'
  what():  bad optional access
Aborted (core dumped)

此处由于没有插入key3,所以get时得到的值为nil,最后输出时抛出了异常。

如果要处理这个情况,那要用到OptionalString的另一个特性。OptionalString可以隐式转化为bool类型,如果元素有效则为true,元素无效则为false

输出之前,只需要判断一下返回值是否为true即可:

cpp 复制代码
int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");

    redis.set("key1", "111");
    redis.set("key2", "222");

    auto ret1 = redis.get("key1");
    if (ret1)
        std::cout << ret1.value() << std::endl;

    auto ret2 = redis.get("key2");
    if (ret2)
        std::cout << ret2.value() << std::endl;

    auto ret3 = redis.get("key3");
    if (ret3)
        std::cout << ret3.value() << std::endl;

    return 0;
}

exists

  • exists用于检测key是否存在,函数声明如下:
cpp 复制代码
long long exists(const StringView &key);

这个很简单,就是判断一个key是否存在。

但是其为什么要以long long作为返回值?其实exists还有另一个函数重载:

cpp 复制代码
template <typename T>
long long exists(std::initializer_list<T> il);

其接收一个初始化列表,也就是可以同时接收多个key,此时有多少个key存在,就返回多少。

示例:

cpp 复制代码
#include <iostream>
#include <sw/redis++/redis++.h>

int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");

    redis.set("key1", "111");
    redis.set("key2", "222");

    std::cout << redis.exists("key1") << std::endl;
    std::cout << redis.exists({"key1", "key2", "key3"}) << std::endl;

    return 0;
}

输出结果:

cpp 复制代码
1
2

此处要注意,输入的是一个初始化列表(C++11),需要用{}把所有参数先包起来,构成一个初始化列表。


del

  • del用于删除key,函数声明如下:
cpp 复制代码
long long del(const StringView &key);

template <typename T>
long long del(std::initializer_list<T> il);

exists一样,支持删除一个或多个key,删除多个时要通过初始化列表。


flushall

  • flushall用于清空整个redis,函数声明如下:
cpp 复制代码
void flushall(bool async = false);

该接口会清空redis内的所有数据,开发环境慎用,一般而言参数直接用默认的false即可。


keys

  • keys用于搜索符合条件的keykeys函数声明如下:
cpp 复制代码
template <typename Output>
void keys(const StringView &pattern, Output output);

keys用于搜索所有符合条件的key,此处第一个参数pattern是匹配模式,output是一个插入迭代器,用于获取符合条件的key,元素类型是字符串,std::string或者StringView

cpp 复制代码
int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    redis.flushall();

    redis.set("key1", "111");
    redis.set("key2", "222");
    redis.set("key3", "222");
    redis.set("key4", "222");

    std::vector<std::string> result;
    auto it = std::back_inserter(result);

    redis.keys("*", it);

    for (auto& ret : result)
        std::cout << ret << std::endl;

    return 0;
}

输出结果:

cpp 复制代码
key3
key2
key1
key4

此处的插入迭代器,是一种专门用于将元素插入到容器中的迭代器,主要有以下三种:

  1. std::front_insert_iterator:在容器头部插入
  2. std::back_insert_iterator:在容器尾部插入
  3. std::insert_iteraotr:在容器任意位置插入

这种迭代器,++--都是无效的,核心是operator=

比如模拟实现一个vector的插入迭代器:

cpp 复制代码
template <typename T>
class InsertIterator {
public:
    // 构造函数,保存容器的引用和插入位置的迭代器
    InsertIterator(std::vector<T>& vec, typename std::vector<T>::iterator pos)
        : vec_(vec), pos_(pos) {}

    // 重载赋值操作符,实现插入逻辑
    InsertIterator& operator=(const T& value) {
        pos_ = vec_.insert(pos_, value);
        return *this;
    }

    // 重载前置和后置增加操作符,因为插入操作不改变迭代器位置
    InsertIterator& operator++() { return *this; }
    InsertIterator& operator++(int) { return *this; }

    // 重载解引用操作符,以便可以链式调用
    InsertIterator& operator*() { return *this; }

private:
    std::vector<T>& vec_;
    typename std::vector<T>::iterator pos_;
};

operator=内部,调用vector.insert接口,完成元素插入容器的操作,此时pos也会自动指向新的位置。

这种迭代器,可以完成插入与容器的解耦合,redis返回的结果集,可以不用重载各种setvector等容器,而是使用统一的插入迭代器完成。


ttl

  • ttl用于获取key的剩余超时时间,函数声明如下:
cpp 复制代码
long long ttl(const StringView &key);

这个函数结合下一个接口一起展示。


expire

  • expire用于设置超时时间,函数声明如下:
cpp 复制代码
bool expire(const StringView &key, long long timeout);
bool expire(const StringView &key, const std::chrono::seconds &timeout);

expire设置超时时间时,有两种模式,第一个重载的timeoutlong long类型,以秒为单位,也可以使用std::chrono::seconds来控制。

返回值与redis原生的ttl完全一致,如果key不存在返回-2,如果key存在但是没有超时时间返回-1

示例:

cpp 复制代码
#include <iostream>
#include <chrono>

#include <sw/redis++/redis++.h>

int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    redis.flushall();

    redis.set("key1", "111");
    redis.set("key2", "222");
    redis.set("key3", "222");

    redis.expire("key1", 10);
    redis.expire("key2", std::chrono::seconds(1));

    std::cout << redis.ttl("key1") << std::endl;
    std::cout << redis.ttl("key2") << std::endl;
    std::cout << redis.ttl("key3") << std::endl;
    std::cout << redis.ttl("key4") << std::endl;

    return 0;
}

输出结果:

cpp 复制代码
10
1
-1
-2

type

  • type用于获取key对于的value的类型,函数声明如下:
cpp 复制代码
std::string type(const StringView &key);

其返回值是标准的std::string


相关推荐
尘浮生4 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君18 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队27 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
怀澈12230 分钟前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
inventecsh43 分钟前
mongodb基础操作
数据库·mongodb
白云如幻1 小时前
SQL99版链接查询语法
数据库·sql·mysql
chnming19871 小时前
STL关联式容器之set
开发语言·c++
威桑1 小时前
MinGW 与 MSVC 的区别与联系及相关特性分析
c++·mingw·msvc
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list