zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Python入门-函数进阶
    Python入门-初始函数
    Leetcode300. Longest Increasing Subsequence最长上升子序列
    Leetcode139. Word Break单词拆分
    Leetcode279. Perfect Squares完全平方数
    Leetcode319. Bulb Switcher灯泡开关
    Leetcode322. Coin Change零钱兑换
    二叉树三种遍历两种方法(递归和迭代)
    Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历
    Leetcode515. Find Largest Value in Each Tree Row在每个树行中找最大值
  • 原文地址:https://www.cnblogs.com/jeakeven/p/5071087.html
Copyright © 2011-2022 走看看