概 述
本文介紹使用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