• Redis --> Redis的接口介绍及使用


    Redis的接口介绍及使用

      Redis是一个远程内存数据库,它不仅性能强劲,而且还具有复制特性以及为解决问题而生的独一无二的数据模型。Redis提供了5种不同类型的数据结构,各式各样的问题都可以很自然地映射到这些数据结构上:Redis的数据结构致力于帮助用户解决问题,而不会像其他数据库那样,要求用户扭曲问题来适应数据库。除此之外,通过复制、持久化(persistence)和客户端分片(client-side sharding)等特性,用户可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。

     

    一、接口说明

    1) 连接数据库

    redisContext* redisConnect(const char *ip, int port)
    redisContext* redisConnectWithTimeout(const char *ip, int port, timeval tv)

    该函数用来连接redis数据库, 两个参数分别是redis数据库的ip和端口,端口号一般为6379。类似的还提供了一个函数,供连接超时限定。

    2)执行命令

    void *redisCommand(redisContext *c, const char *format...)

    该函数用于执行redis数据库中的命令,第一个参数为连接数据库返回的redisContext,剩下的参数为变参,如同C语言中的prinf()函数。此函数的返回值为void*,但是一般会强制转换为redisReply类型,以便做进一步的处理。

    3)释放内存

    void freeReplyObject(void *reply)

    释放redisCommand执行后返回的的redisReply所占用的内存。

    4)断开连接

    void redisFree(redisContext *c)

    释放redisConnect()所产生的连接。

     

    二、Redis的使用

    1、网站下载hiredis.tar.gz包

    2、然后执行make进行编译

    3、把libhiredis.so放到/usr/local/lib/中,把hiredis.h放到/usr/local/inlcude/hiredis/中;或者直接用命令make install配置。

    4、在程序中包含#include <hiredis/hiredis.h>即可。

    示例一:

    redis.h头文件

    #ifndef _REDIS_H_
    #define _REDIS_H_
    
    #include <iostream>
    #include <string.h>
    #include <string>
    #include <stdio.h>
    
    #include <hiredis/hiredis.h>
    
    class Redis
    {
    public:
        Redis(){}
        ~Redis()
       {
            this->_connect = NULL;
            this->_reply = NULL;                
        }
    
        bool connect(std::string host, int port)
        {
            this->_connect = redisConnect(host.c_str(), port);
            if(this->_connect != NULL && this->_connect->err)
            {
                printf("connect error: %s
    ", this->_connect->errstr);
                return 0;
            }
            return 1;
        }
    
        std::string get(std::string key)
        {
            this->_reply = (redisReply*)redisCommand(this->_connect, "GET %s", key.c_str());
            std::string str = this->_reply->str;
            freeReplyObject(this->_reply);
            return str;
        }
    
        void set(std::string key, std::string value)
        {
            redisCommand(this->_connect, "SET %s %s", key.c_str(), value.c_str());
        }
    
    private:
        redisContext* _connect;
        redisReply* _reply;       
    };
    
    #endif  //_REDIS_H_

    主函数

    #include "redis.h"
    
    int main()
    {
       Redis *r = new Redis();
       if(!r->connect("192.168.13.128", 6379))
       {
          printf("connect error!
    ");
          return 0;
       }
       r->set("name", "Mayuyu");
       printf("Get the name is %s
    ", r->get("name").c_str());
       delete r;
       return 0;
    }

    makefile文件

    redis: redis.cpp redis.h
      g++ redis.cpp -o redis -L/usr/local/lib/ -lhiredis
    
    clean:
      rm redis.o redis

    在执行的时候如果出现动态库无法加载:

      1)在 /etc/ld.so.conf.d/ 目录下新建文件 usr-libs.conf ,添加 /usr/local/lib ;

      2)使用命令 /sbin/ldconfig 更新一下配置即可。

     

    示例二:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include <stdarg.h>
    #include <string.h>
    #include <assert.h>
    #include <hiredis.h>
    
    void doTest()
    {
        int timeout = 10000;
        struct timeval tv;
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = timeout * 1000;
        //以带有超时的方式链接Redis服务器,同时获取与Redis连接的上下文对象。
        //该对象将用于其后所有与Redis操作的函数。
        redisContext* c = redisConnectWithTimeout("192.168.149.137",6379,tv);
        if (c->err) {
            redisFree(c);
            return;
        }
        const char* command1 = "set stest1 value1";
        redisReply* r = (redisReply*)redisCommand(c,command1);
        //需要注意的是,如果返回的对象是NULL,则表示客户端和服务器之间出现严重错误,必须重新链接。
        //这里只是举例说明,简便起见,后面的命令就不再做这样的判断了。
        if (NULL == r) {
            redisFree(c);
            return;
        }
        //不同的Redis命令返回的数据类型不同,在获取之前需要先判断它的实际类型。
        //至于各种命令的返回值信息,可以参考Redis的官方文档,或者查看该系列博客的前几篇
        //有关Redis各种数据类型的博客。:)
        //字符串类型的set命令的返回值的类型是REDIS_REPLY_STATUS,然后只有当返回信息是"OK"
        //时,才表示该命令执行成功。后面的例子以此类推,就不再过多赘述了。
        if (!(r->type == REDIS_REPLY_STATUS && strcasecmp(r->str,"OK") == 0)) {
            printf("Failed to execute command[%s].
    ",command1);
            freeReplyObject(r);
            redisFree(c);
            return;
        }
        //由于后面重复使用该变量,所以需要提前释放,否则内存泄漏。
        freeReplyObject(r);
        printf("Succeed to execute command[%s].
    ",command1);
    
        const char* command2 = "strlen stest1";
        r = (redisReply*)redisCommand(c,command2);
        if (r->type != REDIS_REPLY_INTEGER) {
            printf("Failed to execute command[%s].
    ",command2);
            freeReplyObject(r);
            redisFree(c);
            return;
        }
        int length = r->integer;
        freeReplyObject(r);
        printf("The length of 'stest1' is %d.
    ",length);
        printf("Succeed to execute command[%s].
    ",command2);
    
        const char* command3 = "get stest1";
        r = (redisReply*)redisCommand(c,command3);
        if (r->type != REDIS_REPLY_STRING) {
            printf("Failed to execute command[%s].
    ",command3);
            freeReplyObject(r);
            redisFree(c);
            return;
        }
        printf("The value of 'stest1' is %s.
    ",r->str);
        freeReplyObject(r);
        printf("Succeed to execute command[%s].
    ",command3);
    
        const char* command4 = "get stest2";
        r = (redisReply*)redisCommand(c,command4);
        //这里需要先说明一下,由于stest2键并不存在,因此Redis会返回空结果,这里只是为了演示。
        if (r->type != REDIS_REPLY_NIL) {
            printf("Failed to execute command[%s].
    ",command4);
            freeReplyObject(r);
            redisFree(c);
            return;
        }
        freeReplyObject(r);
        printf("Succeed to execute command[%s].
    ",command4);
    
        const char* command5 = "mget stest1 stest2";
        r = (redisReply*)redisCommand(c,command5);
        //不论stest2存在与否,Redis都会给出结果,只是第二个值为nil。
        //由于有多个值返回,因为返回应答的类型是数组类型。
        if (r->type != REDIS_REPLY_ARRAY) {
            printf("Failed to execute command[%s].
    ",command5);
            freeReplyObject(r);
            redisFree(c);
            //r->elements表示子元素的数量,不管请求的key是否存在,该值都等于请求是键的数量。
            assert(2 == r->elements);
            return;
        }
        for (int i = 0; i < r->elements; ++i) {
            redisReply* childReply = r->element[i];
            //之前已经介绍过,get命令返回的数据类型是string。
            //对于不存在key的返回值,其类型为REDIS_REPLY_NIL。
            if (childReply->type == REDIS_REPLY_STRING)
                printf("The value is %s.
    ",childReply->str);
        }
        //对于每一个子应答,无需使用者单独释放,只需释放最外部的redisReply即可。
        freeReplyObject(r);
        printf("Succeed to execute command[%s].
    ",command5);
    
        printf("Begin to test pipeline.
    ");
        //该命令只是将待发送的命令写入到上下文对象的输出缓冲区中,直到调用后面的
        //redisGetReply命令才会批量将缓冲区中的命令写出到Redis服务器。这样可以
        //有效的减少客户端与服务器之间的同步等候时间,以及网络IO引起的延迟。
        //至于管线的具体性能优势,可以考虑该系列博客中的管线主题。
        if (REDIS_OK != redisAppendCommand(c,command1)
            || REDIS_OK != redisAppendCommand(c,command2)
            || REDIS_OK != redisAppendCommand(c,command3)
            || REDIS_OK != redisAppendCommand(c,command4)
            || REDIS_OK != redisAppendCommand(c,command5)) {
            redisFree(c);
            return;
        }
    
        redisReply* reply = NULL;
        //对pipeline返回结果的处理方式,和前面代码的处理方式完全一直,这里就不再重复给出了。
        if (REDIS_OK != redisGetReply(c,(void**)&reply)) {
            printf("Failed to execute command[%s] with Pipeline.
    ",command1);
            freeReplyObject(reply);
            redisFree(c);
        }
        freeReplyObject(reply);
        printf("Succeed to execute command[%s] with Pipeline.
    ",command1);
    
        if (REDIS_OK != redisGetReply(c,(void**)&reply)) {
            printf("Failed to execute command[%s] with Pipeline.
    ",command2);
            freeReplyObject(reply);
            redisFree(c);
        }
        freeReplyObject(reply);
        printf("Succeed to execute command[%s] with Pipeline.
    ",command2);
    
        if (REDIS_OK != redisGetReply(c,(void**)&reply)) {
            printf("Failed to execute command[%s] with Pipeline.
    ",command3);
            freeReplyObject(reply);
            redisFree(c);
        }
        freeReplyObject(reply);
        printf("Succeed to execute command[%s] with Pipeline.
    ",command3);
    
        if (REDIS_OK != redisGetReply(c,(void**)&reply)) {
            printf("Failed to execute command[%s] with Pipeline.
    ",command4);
            freeReplyObject(reply);
            redisFree(c);
        }
        freeReplyObject(reply);
        printf("Succeed to execute command[%s] with Pipeline.
    ",command4);
    
        if (REDIS_OK != redisGetReply(c,(void**)&reply)) {
            printf("Failed to execute command[%s] with Pipeline.
    ",command5);
            freeReplyObject(reply);
            redisFree(c);
        }
        freeReplyObject(reply);
        printf("Succeed to execute command[%s] with Pipeline.
    ",command5);
        //由于所有通过pipeline提交的命令结果均已为返回,如果此时继续调用redisGetReply,
        //将会导致该函数阻塞并挂起当前线程,直到有新的通过管线提交的命令结果返回。
        //最后不要忘记在退出前释放当前连接的上下文对象。
        redisFree(c);
        return;
    }
    
    int main() 
    {
        doTest();
        return 0;
    }
    
    //输出结果如下:
    //Succeed to execute command[set stest1 value1].
    //The length of 'stest1' is 6.
    //Succeed to execute command[strlen stest1].
    //The value of 'stest1' is value1.
    //Succeed to execute command[get stest1].
    //Succeed to execute command[get stest2].
    //The value is value1.
    //Succeed to execute command[mget stest1 stest2].
    //Begin to test pipeline.
    //Succeed to execute command[set stest1 value1] with Pipeline.
    //Succeed to execute command[strlen stest1] with Pipeline.
    //Succeed to execute command[get stest1] with Pipeline.
    //Succeed to execute command[get stest2] with Pipeline.
    //Succeed to execute command[mget stest1 stest2] with Pipeline.

    参考:

    http://blog.csdn.net/achelloworld/article/details/41598389

    http://www.cnblogs.com/stephen-liu74/archive/2012/04/13/2398249.html

  • 相关阅读:
    SpringBoot连接数据库
    String、StringBuffer、StringBulider的区别和解析
    异常This application has no explicit mapping for /error
    node使用
    JS总结defer与async(一)
    前端项目搭建与知识框架
    git ssh配置总结
    JS算法
    JS数据结构
    Http与Http2与Https区别和联系
  • 原文地址:https://www.cnblogs.com/jeakeven/p/5071087.html
Copyright © 2020-2023  润新知