redis的c++ 客户端 redis-plus-plus

hiredis 多线程不安全,要想多线程使用就得维护一个对象池,使用起来比较麻烦

//redis.hpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
// typedef std::vector CharVector;


class RedisClient {
public:
    RedisClient()
    {
    }
    ~RedisClient()
    {
        for (int i = 0; i < conn_num; ++i) {
            if (conn_pool[i] != NULL) {
                redisFree(conn_pool[i]);
                conn_pool[i] = NULL;
            }
        }
        delete[] conn_pool;
		conn_flag.clear();
        // if (conn_flag != NULL) {
        //     delete[] conn_flag;
        //     conn_flag = NULL;
        // }
    }

    int init(std::string ip_, int port_, int conn_num_)
    {
        ip = ip_;
        port = port_;
        conn_num = conn_num_;

        conn_pool = new redisContext*[conn_num];
        if (conn_pool == NULL) {
            return 1;
        }

        conn_flag.reserve(conn_num) ;
        if (conn_flag.capacity() != conn_num) {
            return 2;
        }

        for (int i = 0; i < conn_num; ++i) {
            conn_pool[i] = redisConnect(ip.c_str(), port);
            if (conn_pool[i] == NULL || conn_pool[i]->err) {
                return 3;
            }

            conn_flag[i] = 0;
        }

        empty_num = conn_num;
        current_conn = 0;

        return 0;
    }
	


    bool isConnOk(redisContext* conn);
    // bool Reconnect();
    // bool Conn(const char* ip, int port = 6379);
    // void Close();
    // int checkError();

    // size_t SetHValue(redisContext* conn,std::string& table, std::string& field, const char* value, size_t len);
    // size_t SetHValue(redisContext* conn,std::string& table, std::string& field, std::string& value);
    // int64_t INCR(redisContext* conn,std::string& table, std::string& field, int count);
    // size_t QueryKeys(redisContext* conn,std::string& table, std::vector& vec);
    // size_t QueryKeys(redisContext* conn,std::string& table, std::map& map);
    // size_t Query(redisContext* conn,std::string& table, std::string& field, std::string& value);
    // size_t Query(std::string & table, std::string & field, CharVector & value);
    // size_t QueryCount(string& table);

    // size_t SetHValue(const char * table, const char *  field, const char * value, size_t len);
    size_t Query(const char* table, const char* field, char** pValue );
    // size_t QueryCount(redisContext* conn,const char* table);
    // int64_t INCR(redisContext* conn,const char* table, const char* field, int count);
    // CharVector buffer;

private:
	void set_conn(int id){
		
		if(conn_pool[id] !=NULL){
			redisFree(conn_pool[id]);
		}
		conn_pool[id] = redisConnect(ip.c_str(), port);
        if(conn_pool[id] == NULL || conn_pool[id]->err)
        {
            std::cout << "connect error!" << std::endl;
            return;  
        }
        std::cout << "reconnect" << std::endl;
	}
    redisContext* get_conn(int &out_id)
    {
        if (empty_num == 0) {
            return NULL;
        }

        mtx.lock();

        while (conn_flag[current_conn] != 0) {
            current_conn = (current_conn + 1) % conn_num;
        }

        conn_flag[current_conn] = 1;
        --empty_num;
        out_id = current_conn;
        current_conn = (current_conn + 1) % conn_num;

        mtx.unlock();

        return conn_pool[out_id];
    }

    void put_conn(int id)
    {
        if (id < conn_num && id >= 0) {
            mtx.lock();

            conn_flag[id] = 0;
            ++empty_num;

            mtx.unlock();
        }

        return;
    }

    // redisContext* conn = nullptr;
    // redisReply* getReply; // used for get

    std::string ip;
    int port;
    int conn_num;

    redisContext** conn_pool;
    std::vector<int> conn_flag;
    int empty_num;
    int current_conn;

    std::mutex mtx;
};
//redis.cpp
#include "redis.hpp"
#include 
using namespace robin;
#define MAX_CONN_TIMES 10
#define DEBUG
bool RedisClient::isConnOk(redisContext* conn)
{
    if (conn == nullptr)
        return false;

    // if (checkError() > 0)
    //     return false;

    if (!(conn->flags & REDIS_CONNECTED)) {
        return false;
    }

    bool ret = false;
    redisReply* reply = static_cast<redisReply*>(redisCommand(conn, "PING"));
    if (reply == nullptr)
        return false;

    if (reply->len > 0)
        ret = true;

    freeReplyObject(reply);

    return ret;
}

// bool RedisClient::Reconnect()
// {
//     this->Close();
//     int n = 0;
//     bool ret = Conn(_ip.c_str(), _port);
//     while (ret == false && n < MAX_CONN_TIMES) {
//         ret = Conn(_ip.c_str(), _port);

//         n++;
//     }

//     return ret;
// }

// bool RedisClient::Conn(const char* ip, int port)
// {
//     this->_ip = ip;
//     this->_port = port;
//     if (conn != nullptr)
//         return 0;

//     conn = redisConnect(ip, port);

//     // struct timeval tm;
//     // tm.tv_sec = 2;
//     // tm.tv_sec = 0;
//     // conn = redisConnectWithTimeout(ip, port, tm);
//     if (conn->err) {
//         printf("redis connection error:%s\n", conn->errstr);
//         return false;
//     }

//     return true;
// }

// size_t RedisClient::SetHValue(redisContext* conn,std::string& table, std::string& field, const char* value, size_t len)
// {
//     redisReply* reply = static_cast(
//         redisCommand(conn, "HSET  %b %b %b", table.c_str(), table.size(),
//             field.c_str(),
//             field.size(),
//             value, len));
//     if (reply == nullptr)
//         return 0;

//     size_t ret = 0;
//     if (reply->type == REDIS_REPLY_INTEGER) {
//         ret = reply->integer;
//     }
//     freeReplyObject(reply);
//     return ret;
// }

// size_t RedisClient::SetHValue(redisContext* conn,std::string& table, std::string& field, std::string& value)
// {
//     if (conn == nullptr)
//         return -1;

//     std::string cmd;

//     std::stringstream stream;
//     stream << "HSET " << table << " " << field << " " << value;
//     cmd = stream.str();
//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
//     if (reply == nullptr)
//         return 0;

//     size_t ret = 0;
//     if (reply->type == REDIS_REPLY_INTEGER) {
//         ret = reply->integer;
//     }
//     freeReplyObject(reply);
//     return ret;
// }

// int64_t RedisClient::INCR(redisContext* conn,const char* table, const char* field, int count)
// {
//     if (conn == nullptr)
//         return -1;

//     std::string cmd = "";
//     std::stringstream stream;

//     stream << "hincrby " << table << " " << field << " " << count;

//     cmd = stream.str();
//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
//     if (reply == nullptr)
//         return 0;

//     int64_t ret = reply->integer;
//     freeReplyObject(reply);

//     return ret;
// }

// int64_t RedisClient::INCR(redisContext* conn,std::string& table, std::string& field, int count)
// {
//     return INCR(conn,table.c_str(), field.c_str(), count);
// }
// size_t RedisClient::QueryKeys(redisContext* conn,std::string& table, std::map& map)
// {
//     std::string cmd = "";
//     std::stringstream stream;
//     stream << " HKEYS " << table;
//     cmd = stream.str();

//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
//     size_t len = 0;
//     if (reply == nullptr)
//         return 0;

//     for (size_t i = 0; i < reply->elements; i++) {
//         redisReply* item = *(reply->element + i);
//         uint32_t id = atoi(item->str);
//         map.insert(std::pair(id, item->str));
//         if (id > len)
//             len = id;
//     }

//     freeReplyObject(reply);
//     return len;
// }

// size_t RedisClient::QueryKeys(redisContext* conn,std::string& table, std::vector& vec)
// {
//     std::string cmd = "";
//     std::stringstream stream;
//     stream << " HKEYS " << table;
//     cmd = stream.str();

//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
//     if (reply == nullptr)
//         return 0;

//     size_t len = reply->elements;
//     for (size_t i = 0; i < reply->elements; i++) {
//         redisReply* item = *(reply->element + i);
//         vec.push_back(item->str);
//         // item->str;
//     }

//     freeReplyObject(reply);
//     return len;
// }

// size_t RedisClient::QueryCount(redisContext* conn,const char* table)
// {
//     std::string cmd = "";
//     std::stringstream stream;
//     stream << " HLEN " << table;
//     cmd = stream.str();

//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));

//     if (reply == nullptr)
//         return 0;

//     //_atoi64(char *)
//     // char *end;
//     // strtoll(reply->str, &end, 10);
//     size_t len = reply->integer;

//     freeReplyObject(reply);
//     return len;
// }
// size_t RedisClient::QueryCount(string& table)
// {
//     return QueryCount(table.c_str());
// }

// size_t RedisClient::Query(redisContext* conn,std::string& table, std::string& field, std::string& value)
// {
//     std::string cmd = "";
//     std::stringstream stream;
//     stream << " HGET " << table << " " << field;
//     cmd = stream.str();
//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));

//     if (reply == nullptr)
//         return 0;

//     size_t len = reply->len;
//     value = reply->str;

//     freeReplyObject(reply);
//     return len;
// }
// size_t RedisClient::Query(std::string& table, std::string& field, CharVector& value)
// {
//     std::string cmd = "";
//     std::stringstream stream;
//     stream << " HGET " << table << " " << field;
//     cmd = stream.str();
//     redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
//     if (reply == nullptr)
//         return 0;

//     size_t len = reply->len;
//     value.reserve(len);
//     value.append(reply->str, len);

//     freeReplyObject(reply);
//     return len;
// }

size_t RedisClient::Query(const char* table, const char* field, char** pValue)
{
    int current_conn = 0;
    redisContext* conn = get_conn(current_conn);
    #ifdef DEBUG
    bool res = isConnOk(conn);
    cout<<res<<endl;
    if(!res){
        set_conn(current_conn);
    }
    #endif
    std::string cmd = "";
    std::stringstream stream;
    stream << " HGET " << table << " " << field;
    cmd = stream.str();

    // if (getReply)
    //     freeReplyObject(getReply);

    redisReply* getReply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));
    if (getReply == nullptr)
        return 0;
    return 0;

    *pValue = getReply->str;
    size_t len = getReply->len;
    put_conn(current_conn);
    return len;
}

// void RedisClient::Close()
// {
//     if (getReply != nullptr) {
//         freeReplyObject(getReply);
//         getReply = nullptr;
//     }
//     if (conn != nullptr) {
//         redisFree(conn);
//         conn = nullptr;
//     }
// }

// int RedisClient::checkError()
// {
//     if (conn->err == REDIS_ERR_IO || conn->err == REDIS_ERR_EOF) {
//         return 1;
//     }

//     return 0;
// }


使用redis-plus-plus来操作redis更加的分布,redis类多线程安全,内部维护了一个连接池
demo


#include 
#include 
#include 
#include 
#include 

extern "C" {
#include  // for getopt on non-Windows platform
}

std::string host = "127.0.0.1";
int port = 6379;
std::string auth;
std::string cluster_node;
int cluster_port = 0;
bool benchmark = false;
int resp = 3;

int main(){
    sw::redis::Optional<sw::redis::ConnectionOptions> opts;
    if (!host.empty() && port > 0) {
        sw::redis::ConnectionOptions tmp;
        tmp.host = host;
        tmp.port = port;
        tmp.password = auth;
        tmp.resp = resp;

        opts = sw::redis::Optional<sw::redis::ConnectionOptions>(tmp);
    }
    if(opts.has_value()){
        sw::redis::Redis redis(*opts);
        redis.set("hello", "world");
        std::string value;
        auto stringopts = redis.get("hello2");
        if(stringopts.has_value()){
            value = *stringopts;
        }
        std::cout<<value<<std::endl;
    }
}

你可能感兴趣的:(c++,redis,c++,数据库)