Redis Client 使用说明

功能描述

  • 依赖Redis官方提供的C库客户端hiredis
  • 支持单主机(single node mode)与集群模式(cluster mode)
  • 支持管道(pipeline)模式
  • 使用连接池
  • 线程安全
  • 自动连接
  • 不支持Windows

使用准备

  • 如果你要运行main.cpp执行测试用例,执行 mkdir build && cd build && cmake .. && make && ./redis-client 即可完成编译运行。
  • 如果你要在 cpp-ethereum 项目中使用此功能。比如,你想在 libjujsonrpc 中使用。那么请在 libjujsonrpcCMakeLists.txt 中添加头文件 target_include_directories(jujsonrpc PRIVATE ${HIREDIS_INCLUDE_DIR}) 以及库文件 target_link_libraries(jujsonrpc ${HIREDIS_LIBRARY}) 。当然,有些可能因为他所包含的文件已经包含了该头文件与库,不需要添加。还有,不要忘记添加需要使用的头文件#include "libjuredisclient/RedisClient.h"。需要注意的是,因为把Redis作为一项服务,所以已经在文件 jueth/main.cpp 文件中已经调用了 redis->Initialize("127.0.0.1", chainParams.m_redis_port, 2, 10) 从而执行Redis客户端连接服务端等一些初始化工作。所以你在其他地方再使用Redis做操作的时候,只需要使用代码CRedisClient::Instance()获取一个指针实例之后就可以直接使用,不再需要执行初始化的工作。当然,如果你需要连接与默认不一样的Redis地址与端口,那么你需要使用CRedisClient()构造一个实例,再用此实例进行初始化才能调用Redis的操作。
  • 如果你需要使用 hiredis 库文件,库文件在lib目录下面。

代码示例

#include <string>
#include "RedisClient.h"

int main(int argc, char **argv) {
    CRedisClient* redisCli = CRedisClient::Instance();

    if (!redisCli->Initialize("127.0.0.1", 6379, 2, 10))
    {
        std::cout << "connect to redis failed" << std::endl;
        return -1;
    }

    std::string strKey = "name";
    std::string strVal;
    if (redisCli->Get(strKey, &strVal) == RC_SUCCESS)
    {
        std::cout << strKey << " has value " << strVal << std::endl;
        return 0;
    }
    else
    {
        std::cout << "request failed" << std::endl;
        return -1;
    }

    return 0;
}

更多测试用例,请看test目录。

待办事项

  • 实现ScanHscan接口,也就意味着目前这两个接口不支持。

接口一览

先说一下调用接口的一些返回值,在后面文档均用RequestRet描述。

Macro definition Value Description
RC_RESULT_EOF 5 无结果再可取
RC_OBJ_NOT_EXIST 3 对象不存在
RC_OBJ_EXIST 2 对象存在
RC_PART_SUCCESS 1 部分调用成功
RC_SUCCESS 0 调用成功
RC_PARAM_ERR -1 参数错误
RC_REPLY_ERR -2 调用返回类型错误
RC_RQST_ERR -3 重连失败
RC_NO_RESOURCE -4 无连接
RC_PIPELINE_ERR -5 ppLine 传参错误
RC_NOT_SUPPORT -6 Redis不支持或未实现

static CRedisClient* Instance()
CRedisClient()
// nTimeout: 连接超时时间,单位秒。nConnNum:连接池数目
bool Initialize(const std::string &strHost, int nPort, int nTimeout, int nConnNum)
bool IsCluster()

Pipeline CreatePipeline()
int FlushPipeline(Pipeline ppLine)
int FetchReply(Pipeline ppLine, long *pnVal)
int FetchReply(Pipeline ppLine, std::string *pstrVal)
int FetchReply(Pipeline ppLine, std::vector<long> *pvecLongVal)
int FetchReply(Pipeline ppLine, std::vector<std::string> *pvecStrVal)
int FetchReply(Pipeline ppLine, redisReply **pReply)
void FreePipeline(Pipeline ppLine)

/* interfaces for generic */
Redis 键命令用于管理 redis 的键。
int Del(const std::string &strKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Dump(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Exists(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Expire(const std::string &strKey, long nSec, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Expireat(const std::string &strKey, long nTime, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Keys(const std::string &strPattern, std::vector<std::string> *pvecVal)
int Persist(const std::string &strKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Pexpire(const std::string &strKey, long nMilliSec, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Pexpireat(const std::string &strKey, long nMilliTime, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Pttl(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Randomkey(std::string *pstrVal, Pipeline ppLine = nullptr)
int Rename(const std::string &strKey, const std::string &strNewKey)
int Renamenx(const std::string &strKey, const std::string &strNewKey)
int Restore(const std::string &strKey, long nTtl, const std::string &strVal, Pipeline ppLine = nullptr)
int Scan(long *pnCursor, const std::string &strPattern, long nCount, std::vector<std::string> *pvecVal)
int Ttl(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Type(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)

/* interfaces for string */
Redis 字符串数据类型的相关命令用于管理 redis 字符串值。
int Append(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Bitcount(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Bitcount(const std::string &strKey, long nStart, long nEnd, long *pnVal, Pipeline ppLine = nullptr)
int Bitop(const std::string &strDestKey, const std::string &strOp, const std::vector<std::string> &vecKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Bitpos(const std::string &strKey, long nBitVal, long *pnVal, Pipeline ppLine = nullptr)
int Bitpos(const std::string &strKey, long nBitVal, long nStart, long nEnd, long *pnVal, Pipeline ppLine = nullptr)
int Decr(const std::string &strKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Decrby(const std::string &strKey, long nDecr, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Get(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Getbit(const std::string &strKey, long nOffset, long *pnVal, Pipeline ppLine = nullptr)
int Getrange(const std::string &strKey, long nStart, long nEnd, std::string *pstrVal, Pipeline ppLine = nullptr)
int Getset(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Incr(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Incrby(const std::string &strKey, long nIncr, long *pnVal, Pipeline ppLine = nullptr)
int Incrbyfloat(const std::string &strKey, double dIncr, double *pdVal, Pipeline ppLine = nullptr)
int Mget(const std::vector<std::string> &vecKey, std::vector<std::string> *pvecVal)
int Mset(const std::vector<std::string> &vecKey, const std::vector<std::string> &vecVal)
int Psetex(const std::string &strKey, long nMilliSec, const std::string &strVal, Pipeline ppLine = nullptr)
int Set(const std::string &strKey, const std::string &strVal, Pipeline ppLine = nullptr)
int Setbit(const std::string &strKey, long nOffset, bool bVal, Pipeline ppLine = nullptr)
int Setex(const std::string &strKey, long nSec, const std::string &strVal, Pipeline ppLine = nullptr)
int Setnx(const std::string &strKey, const std::string &strVal, Pipeline ppLine = nullptr)
int Setrange(const std::string &strKey, long nOffset, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Strlen(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)

/* interfaces for list */
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
一个列表最多可以包含2的32次方-1个元素(4294967295, 每个列表超过40亿个元素)。
int Blpop(const std::string &strKey, long nTimeout, std::vector<std::string> *pvecVal)
int Blpop(const std::vector<std::string> &vecKey, long nTimeout, std::vector<std::string> *pvecVal)
int Brpop(const std::string &strKey, long nTimeout, std::vector<std::string> *pvecVal)
int Brpop(const std::vector<std::string> &vecKey, long nTimeout, std::vector<std::string> *pvecVal)
int Lindex(const std::string &strKey, long nIndex, std::string *pstrVal, Pipeline ppLine = nullptr)
int Linsert(const std::string &strKey, const std::string &strPos, const std::string &strPivot, const std::string &strVal, long *pnVal, Pipeline ppLine = nullptr)
int Llen(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Lpop(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Lpush(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Lpush(const std::string &strKey, const std::vector<std::string> &vecVal, Pipeline ppLine = nullptr)
int Lpushx(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Lrange(const std::string &strKey, long nStart, long nStop, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Lrem(const std::string &strKey, long nCount, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Lset(const std::string &strKey, long nIndex, const std::string &strVal, Pipeline ppLine = nullptr)
int Ltrim(const std::string &strKey, long nStart, long nStop, Pipeline ppLine = nullptr)
int Rpop(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Rpush(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Rpush(const std::string &strKey, const std::vector<std::string> &vecVal, Pipeline ppLine = nullptr)
int Rpushx(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)

/* interfaces for set */
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为2的32次方-1个元素(4294967295, 每个集合可存储40多亿个成员)。
int Sadd(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline = nullptr)
int Scard(const std::string &strKey, long *pnVal, Pipeline = nullptr)
int Sdiff(const std::vector<std::string> &vecKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr);
int Sinter(const std::vector<std::string> &vecKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr);
int Sismember(const std::string &strKey, const std::string &strVal, long *pnVal, Pipeline ppLine = nullptr)
int Smembers(const std::string &strKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Spop(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)
int Srandmember(const std::string &strKey, long nCount, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Srem(const std::string &strKey, const std::string &strVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Srem(const std::string &strKey, const std::vector<std::string> &vecVal, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Sunion(const std::vector<std::string> &vecKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr);

/* interfaces for hash */
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储2的32次方-1个键值对(40多亿)。
int Hdel(const std::string &strKey, const std::string &strField, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Hexists(const std::string &strKey, const std::string &strField, long *pnVal, Pipeline ppLine = nullptr)
int Hget(const std::string &strKey, const std::string &strField, std::string *pstrVal, Pipeline ppLine = nullptr)
int Hgetall(const std::string &strKey, std::map<std::string, std::string> *pmapFv, Pipeline ppLine = nullptr)
int Hincrby(const std::string &strKey, const std::string &strField, long nIncr, long *pnVal, Pipeline ppLine = nullptr)
int Hincrbyfloat(const std::string &strKey, const std::string &strField, double dIncr, double *pdVal, Pipeline ppLine = nullptr)
int Hkeys(const std::string &strKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Hlen(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)
int Hmget(const std::string &strKey, const std::vector<std::string> &vecField, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Hmget(const std::string &strKey, const std::vector<std::string> &vecField, std::map<std::string, std::string> *pmapVal)
int Hmget(const std::string &strKey, const std::set<std::string> &setField, std::map<std::string, std::string> *pmapVal)
int Hmset(const std::string &strKey, const std::vector<std::string> &vecField, const std::vector<std::string> &vecVal, Pipeline ppLine = nullptr)
int Hmset(const std::string &strKey, const std::map<std::string, std::string> &mapFv, Pipeline ppLine = nullptr)
int Hscan(const std::string &strKey, long *pnCursor, const std::string &strMatch, long nCount, std::vector<std::string> *pvecVal);
int Hset(const std::string &strKey, const std::string &strField, const std::string &strVal, Pipeline ppLine = nullptr)
int Hsetnx(const std::string &strKey, const std::string &strField, const std::string &strVal, Pipeline ppLine = nullptr)
int Hvals(const std::string &strKey, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)

/* interfaces for sorted set */
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为2的32次方-1个(4294967295, 每个集合可存储40多亿个成员)。
int Zadd(const std::string &strKey, double dScore, const std::string &strElem, long *pnVal = nullptr, Pipeline = nullptr)
int Zcard(const std::string &strKey, long *pnVal, Pipeline = nullptr)
int Zcount(const std::string &strKey, double dMin, double dMax, long *pnVal, Pipeline ppLine = nullptr)
int Zincrby(const std::string &strKey, double dIncr, const std::string &strElem, double *pdVal, Pipeline ppLine = nullptr)
int Zlexcount(const std::string &strKey, const std::string &strMin, const std::string &strMax, long *pnVal, Pipeline ppLine = nullptr)
int Zrange(const std::string &strKey, long nStart, long nStop, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Zrangewithscore(const std::string &strKey, long nStart, long nStop, std::map<std::string, std::string> *pmapVal, Pipeline ppLine = nullptr)
int Zrangebylex(const std::string &strKey, const std::string &strMin, const std::string &strMax, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Zrangebyscore(const std::string &strKey, double dMin, double dMax, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Zrangebyscore(const std::string &strKey, double dMin, double dMax, std::map<std::string, double> *pmapVal, Pipeline ppLine = nullptr)
int Zrank(const std::string &strKey, const std::string &strElem, long *pnVal, Pipeline ppLine = nullptr)
int Zrem(const std::string &strKey, const std::string &strElem, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Zrem(const std::string &strKey, const std::vector<std::string> &vecElem, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Zremrangebylex(const std::string &strKey, const std::string &strMin, const std::string &strMax, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Zremrangebyrank(const std::string &strKey, long nStart, long nStop, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Zremrangebyscore(const std::string &strKey, double dMin, double dMax, long *pnVal = nullptr, Pipeline ppLine = nullptr)
int Zrevrange(const std::string &strKey, long nStart, long nStop, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Zrevrangebyscore(const std::string &strKey, double dMax, double dMin, std::vector<std::string> *pvecVal, Pipeline ppLine = nullptr)
int Zrevrangebyscore(const std::string &strKey, double dMax, double dMin, std::map<std::string, double> *pmapVal, Pipeline ppLine = nullptr)
int Zrevrank(const std::string &strKey, const std::string &strElem, long *pnVal, Pipeline ppLine = nullptr)
int Zscore(const std::string &strKey, const std::string &strElem, double *pdVal, Pipeline ppLine = nullptr)

/* interfaces for system */
Redis 服务器命令主要是用于管理 redis 服务(只实现一个)。
int Time(struct timeval *ptmVal, Pipeline ppLine = nullptr)

API 使用详细说明

static CRedisClient* Instance()

获取单例指针。

CRedisClient()

构造函数,构造一个CRedisClient对象。

bool Initialize(const std::string &strHost, int nPort, int nTimeout, int nConnNum)

初始化链接。strHost:服务器IP。nPort:服务器端口。nTimeout: 连接超时时间,单位秒。nConnNum:连接池数目


int Del(const std::string &strKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)

删除键。strKey:键。pnVal:被删除键的个数。ppLine:管道。

int Dump(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)

序列化给定 key ,并返回被序列化的值。strKey:键。pstrVal:序列化后的值。ppLine:管道。

int Exists(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)

key是否存在。strKey:键。pnVal:若为1则key存在,为0则不存在。ppLine:管道。

int Expire(const std::string &strKey, long nSec, long *pnVal = nullptr, Pipeline ppLine = nullptr)

设置key的过期时间,超过时间后,将会自动删除该key。strKey:键。nSec:过期时间,单位秒。pnVal:1 如果成功设置过期时间,0 如果key不存在或者不能设置过期时间。ppLine:管道。

int Expireat(const std::string &strKey, long nTime, long *pnVal = nullptr, Pipeline ppLine = nullptr)

设置key的过期时间,超过时间后,将会自动删除该key。参考Expire,不同的是命令接受的时间参数是 UNIX 时间戳 Unix timestamp。

int Keys(const std::string &strPattern, std::vector<std::string *pvecVal)

查找所有符合给定模式pattern(正则表达式)的 key。strPattern:键的正则表达模式。pvecVal:所有符合条件的key。

int Persist(const std::string &strKey, long *pnVal = nullptr, Pipeline ppLine = nullptr)

移除给定key的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。strKey:键。pnVal:当生存时间移除成功时,返回 1。如果 key 不存在或 key 没有设置生存时间,返回 0 。ppLine:管道。

int Pexpire(const std::string &strKey, long nMilliSec, long *pnVal = nullptr, Pipeline ppLine = nullptr)

设置key的过期时间,超过时间后,将会自动删除该key。参考Expire,不同的是它以毫秒为单位设置 key 的生存时间。

int Pexpireat(const std::string &strKey, long nMilliTime, long *pnVal = nullptr, Pipeline ppLine = nullptr)

设置key的过期时间,超过时间后,将会自动删除该key。参考Pexpire,不同的是它以毫秒为单位设置 key 的过期 UNIX 时间戳。

int Pttl(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)

以毫秒为单位返回 key 的剩余生存时间。strKey:键。pnVal:如果key不存在返回-2,如果key存在且无过期时间返回-1 。ppLine:管道。

int Pttl(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)

以毫秒为单位返回 key 的剩余生存时间。strKey:键。pnVal:如果key不存在返回-2,如果key存在且无过期时间返回-1 。ppLine:管道。

int Randomkey(std::string *pstrVal, Pipeline ppLine = nullptr)

从当前数据库返回一个随机的key。pstrVal:返回的键值。ppLine:管道。

int Rename(const std::string &strKey, const std::string &strNewKey)

将key重命名为newkey,如果key与newkey相同,将返回一个错误RC_REPLY_ERR。如果newkey已经存在,则值将被覆盖。strKey:旧键值。strNewKey:新键值。

int Renamenx(const std::string &strKey, const std::string &strNewKey)

当且仅当 newkey 不存在时,将 key 改名为 newkey。strKey:旧键值。strNewKey:新键值。如果修改失败(如当 key 不存在时, newKey已存在),返回RC_REPLY_ERR。

int Restore(const std::string &strKey, long nTtl, const std::string &strVal, Pipeline ppLine = nullptr)

反序列化给定的序列化值,并将它和给定的 key 关联。strKey:旧键值。nTtl:毫秒为单位为 key 设置生存时间。ppLine:管道。

int Scan(long *pnCursor, const std::string &strPattern, long nCount, std::vector<std::string> *pvecVal)

迭代当前数据库中的key集合。pnCursor:游标。strPattern:正则表达式。nCount:数量。pvecVal:值。

int Ttl(const std::string &strKey, long *pnVal, Pipeline ppLine = nullptr)

以秒为单位返回 key 的剩余生存时间。strKey:键。pnVal:如果key不存在返回-2,如果key存在且无过期时间返回-1 。ppLine:管道。

int Type(const std::string &strKey, std::string *pstrVal, Pipeline ppLine = nullptr)

返回key所存储的value的数据结构类型,它可以返回string, list, set, zset 和 hash等不同的类型。strKey:键。pstrVal:类型,不存在返回none。ppLine:管道。