C++ 實現(xiàn)數(shù)據(jù)庫連接池

概 述

本文介紹使用C++實現(xiàn)數(shù)據(jù)庫連接池。
連接池的基本思想就是在初始化時,將數(shù)據(jù)庫連接對象保存在內(nèi)存中,當用戶需要訪問數(shù)據(jù)庫時,并非新建一個連接,而是從連接池中取出一個空閑的連接對象;使用完畢后,也并非直接斷開連接,而是重新放到連接池中。以達到避免頻繁連接斷開數(shù)據(jù)庫,提高數(shù)據(jù)庫的處理效率。

實 現(xiàn)

根據(jù)連接池的基本思想,我們設(shè)計一個數(shù)據(jù)庫連接池,如下:

  • 單例模式,保證進程唯一
  • 使用queue來管理數(shù)據(jù)庫連接對象(靜態(tài)大小)
  • 互斥鎖實現(xiàn)線程安全

基于queue實現(xiàn)一個靜態(tài)大小的簡單數(shù)據(jù)庫連接池,示例代碼如下:

//SqlConnPool.h
#include <string>
#include <queue>
#include <mutex>
#include <mysql/mysql.h>

class SqlConnPool {
public:
    static SqlConnPool *GetInstance(); //單例

    void Init(const std::string& host, int port,
              const std::string& user, const std::string& pwd,
              const std::string& db_name, int conn_size);
    void ClosePool();

    MYSQL *GetConnObj(); //獲取連接對象
    void FreeConnObj(MYSQL *conn); //釋放連接對象

private:
    SqlConnPool();
    ~SqlConnPool();

private:
    std::queue<MYSQL *> m_connQue; //連接對象隊列

    int m_max_conn; //最大連接數(shù)
    std::mutex m_mutex; //互斥量
};

//SqlConnPool.cpp
#include "../Log/Log.h"
#include "SqlConnPool.h"

SqlConnPool::SqlConnPool() {
}

SqlConnPool::~SqlConnPool() {
    ClosePool();
}

SqlConnPool *SqlConnPool::GetInstance() {
    static SqlConnPool sqlConnPool;
    return &sqlConnPool;
}

void SqlConnPool::Init(const std::string& host, int port, const std::string& user,
        const std::string& pwd, const std::string& db_name, int conn_size) {
    for (int i = 0; i < conn_size; i++) {
        MYSQL *sql = nullptr;
        sql = mysql_init(sql);
        if (!sql) {
            LOG_ERROR("MySql init error!");
        }

        sql = mysql_real_connect(sql, host.c_str(), user.c_str(), pwd.c_str(), db_name.c_str(), port, nullptr, 0);
        if (!sql) {
            LOG_ERROR("MySql Connect error!");
        }
        m_connQue.push(sql);
    }
    m_max_conn = conn_size;
}

MYSQL *SqlConnPool::GetConnObj() {
    MYSQL *sql = nullptr;
    if (m_connQue.empty()) {
        LOG_WARN("SqlConnPool busy!");
        return nullptr;
    }

    {
        std::lock_guard<std::mutex> locker(m_mutex);
        sql = m_connQue.front();
        m_connQue.pop();
    }

    return sql;
}

void SqlConnPool::FreeConnObj(MYSQL *conn) {
    if (conn != nullptr) {
        std::lock_guard<std::mutex> locker(m_mutex);
        m_connQue.push(conn);
    }
}

void SqlConnPool::ClosePool() {
    std::lock_guard<std::mutex> locker(m_mutex);
    while(!m_connQue.empty()) {
        auto item = m_connQue.front();
        m_connQue.pop();
        mysql_close(item);
    }
    mysql_library_end();
}

這個數(shù)據(jù)庫連接池提供了連接對象的獲取和釋放接口,但是在實際使用中,需要使用者記得在使用完畢后去釋放連接對象,這樣的設(shè)計并不友好,因此我們添加一個數(shù)據(jù)庫操作類,利用RAII來封裝下數(shù)據(jù)庫連接池,這樣可以確保在使用完連接對象后,操作類會幫助我們析構(gòu)釋放對象。示例代碼如下:

// SqlHandler.h
#include "SqlConnPool.h"

class SqlHandler {
public:
    SqlHandler(SqlConnPool *connpool);
    SqlHandler(MYSQL **sql, SqlConnPool *connpool);
    ~SqlHandler();

private:
    MYSQL *m_sql;
    SqlConnPool *m_connpool;
};

// SqlHandler.cpp
#include "SqlHandler.h"

SqlHandler::SqlHandler(SqlConnPool *connpool) {
    if (connpool) {
        m_sql = connpool->GetConnObj();
        m_connpool = connpool;
    }
}

SqlHandler::SqlHandler(MYSQL **sql, SqlConnPool *connpool) {
    if (connpool) {
        *sql = connpool->GetConnObj();
        m_sql = *sql;
        m_connpool = connpool;
    }
}

SqlHandler::~SqlHandler() {
    if (m_sql) {
        m_connpool->FreeConnObj(m_sql);
    }
}

更多內(nèi)容,詳見github NetLib

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容