数据库连接池类
- 使用池的原因是因为数据库的连接和释放很消耗资源,如果每次需要数据库的时候再进行连接非常耗时。
- 使用单例模式
class connection_pool
接口:
- static connect_pool *GetInstance() :单例模式,获取数据库池对象指针
- void init(…):数据库初始化,输入数据库的用户密码和对哪个数据库进行操作。
- MYSQL *GetConnection() :获取数据库连接 ,无可用连接时候会阻塞。
- bool ReleaseConnection(MYSQL*) :把之前获取到的数据库连接放回去。
- int GetFreeConn():当前连接池有多少可用连接。
实现
#include "mysql/mysql.h"
#include "../lock/locker.h"
#include "list"
#include "string"
class connection_pool{
public:
static connection_pool *GetInstance();
void init(std::string host, int port, std::string user_name, std::string password, std::string db_name, int max_conn);
MYSQL *GetConnection();
bool ReleaseConnection(MYSQL* &);
int GetFreeConn(){
return m_free_conn;
}
private:
connection_pool();
~connection_pool();
private:
std::list<MYSQL*> m_list;
int m_free_conn;
sem m_sem;
locker m_locker;
};
connection_pool::connection_pool():m_free_conn(0){}
connection_pool::~connection_pool(){
MutexLockGuard lock(m_locker);
for(auto iter = m_list.begin(); iter != m_list.end(); ++iter){
if(*iter != nullptr)
mysql_close(*iter);
}
}
connection_pool *connection_pool::GetInstance(){
static connection_pool m_instance;
return &m_instance;
}
void connection_pool::init(std::string host, int port, std::string user_name, std::string password, std::string db_name, int max_conn){
MutexLockGuard lock(m_locker);
if(max_conn <= 0)
max_conn = 3;
for(int i = 0; i != max_conn; ++i){
MYSQL *mysql_handler = nullptr;
mysql_handler = mysql_init(mysql_handler);
if(!mysql_handler){
printf("mysql connect error\n");
continue;
}
mysql_handler = mysql_real_connect(mysql_handler, host.c_str(), user_name.c_str(), password.c_str(), db_name.c_str(), port, nullptr, 0);
if(!mysql_handler){
printf("mysql connect error\n");
continue;
}
m_list.push_back(mysql_handler);
++m_free_conn;
}
m_sem = sem(m_free_conn);
}
MYSQL *connection_pool::GetConnection(){
MYSQL *res = nullptr;
if(m_list.empty())
return res;
m_sem.wait();
{
MutexLockGuard lock(m_locker);
res = m_list.front();
m_list.pop_front();
--m_free_conn;
}
return res;
}
bool connection_pool::ReleaseConnection(MYSQL *&conn){
if(conn == nullptr) return false;
MutexLockGuard lock(m_locker);
m_list.push_back(conn);
++m_free_conn;
m_sem.post();
conn = nullptr;
return true;
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
要点:
- 单例模式采用的是C++0x之后才支持的线程安全的static初始化的一个操作,也就是
connection_pool *connection_pool::GetInstance(){
static connection_pool m_instance;
return &m_instance;
}
- 在析构函数的时候关闭mysql连接,由于对数据库连接池采用的是单例模式,所以之后进程结束才会进行析构,也就不用考虑有些mysql连接还没释放的情况了。
for(auto iter = m_list.begin(); iter != m_list.end(); ++iter){
if(*iter != nullptr)
mysql_close(*iter);
}
- 释放连接的时候对MYSQL*参数使用的是引用传参,并且在放回m_list之后回把参数置nullptr,这样就防止了一边把数据库资源还给连接池,一边继续使用的情况发生。
bool connection_pool::ReleaseConnection(MYSQL *&conn){
if(conn == nullptr) return false;
MutexLockGuard lock(m_locker);
m_list.push_back(conn);
++m_free_conn;
m_sem.post();
conn = nullptr;
return true;
}
总结:
- 使用之前要先init()初始化,并且注意init函数不能多次调用,多次调用会引发不可预测的后果。
- 使用GetConnection()获取一个MYSQL*数据库连接,获取连接的时候不会阻塞,当发现连接池中没有可用连接后,直接返回nullptr。
- ReleaseConnection()释放一个MYSQL*连接。
添加:使用RAII管理数据库连接池,用来自动释放连接。
- 使用数据库连接池初始化ConnectRAII,初始化之后的ConnectRAII对象会持有一个数据库连接对象,通过getConn获取这个对象,当离开作用域后,这个对象会自己释放。
class ConnectRAII{
public:
ConnectRAII(connection_pool* connectpool){
m_mysql = connectpool->GetConnection();
m_conn_pool = connectpool;
}
~ConnectRAII(){
m_conn_pool->ReleaseConnection(m_mysql);
}
MYSQL* getConn(){
return m_mysql;
}
private:
MYSQL* m_mysql;
connection_pool* m_conn_pool;
};