思想:封装mysql基本操作API,以stl中的list容器包装连接对象,采用单例模式创建连接池类对象,采取RAII机制进行实现。其中,涉及到对连接队列的操作的,全部都加上互斥锁,保证原子操作。
具体的,Pool类成员变量包括:
主机名或IP地址m_url,如果NULL或"localhost",连接将被视为与本地主机的连接。
数据库名称m_dbName、
登录用户名m_dbUser、
用户密码m_dbPswd、
连接端口m_port,
当前连接数m_curconn、
空闲连接数m_freeconn以及一个封装了互斥量的locker类对象Lock,封装了信号量的sem类对象rest。
主要接口有:
初始化接口init,
获取空闲连接数接口getFreeconn,
释放一个连接接口releaseConn,
销毁连接池接口Destroy以及
单例模式获取唯一实例接口getInstance。
最后,RAIIPool类实现RAII机制,在构造函数中获取唯一实例,析构函数销毁连接池。
代码如下
#pragma once
class Pool{
public:
~Pool();
int getFreeconn();
bool init(string url, string dbName, string dbPswd, string User, int port);
void Destroy(); //销毁连接池
void releaseConn(MYSQL* conn); //释放一个连接
MYSQL* GetConn(); //获取一个空闲连接
Pool* getInstance(); //单例连接
private:
Pool();
list<MYSQL*> pool_;
string m_dbName;
string m_dbPswd;
string m_dbUser;
string m_port;
string m_url;
constexpr static int maxconn = 10; //最大连接
int m_curconn;
int m_freeconn; //空闲连接
locker Lock; //原子操作
sem rest; //信号量类检测剩余空闲连接数
};
//真正实现RAII - 创建对象即获得一个连接, 析构函数则释放资源
class RAIIPool{
public:
RAIIPool(MYSQL** conn, Pool* pool_);
~RAIIPool();
private:
MYSQL* RAIIconn;
Pool* RAIIpool;
};
具体实现:
Pool::Pool(){
this->m_freeconn = 0;
this->m_curconn = 0;
}
Pool::~Pool(){
Destroy();
}
int Pool::getFreeconn(){
return m_freeconn;
}
bool Pool::init(string url, string dbName, string dbPswd, string dbUser, int port){
m_url = url;
m_dbName = dbName;
m_port = port;
m_dbPswd = dbPswd;
m_dbUser = dbUser;
for(int i = 0; i < maxconn; ++i){
MYSQL* conn = NULL;
conn = mysql_init(conn);
if(conn == NULL){
perror("mysql_init");
exit(1);
}
conn = mysql_real_connect(conn, url.c_str(), dbUser.c_str(), dbPswd.c_str(), dbName.c_str(), port, NULL, 0);
if(conn == NULL){
perror("mysql_real_connect");
exit(1);
}
pool_.push_back(conn);
++m_freeconn;
}
rest = sem(m_freeconn);
return true;
}
void Pool::Destroy(){
Lock.lock();
for(auto it = pool_.begin(); it != pool_.end(); ++it){
MYSQL* item = *it;
mysql_close(item);
}
m_curconn = 0;
m_freeconn = 0;
pool_.clear(); //清空list
list<MYSQL*>().swap(pool_); //释放资源
Lock.unlock();
}
MYSQL* Pool::GetConn(){
if(pool_.size() == 0){
return nullptr;
}
Lock.lock();
rest.wait(); //信号量-1
MYSQL* conn = pool_.front(); //取出一个连接
pool_.pop_front();
--m_freeconn;
++m_curconn;
Lock.unlock();
return conn;
}
void Pool::releaseConn(MYSQL* conn){
if(conn == NULL){
return;
}
Lock.lock();
pool_.push_back(conn); //放进空闲链接队列
++m_freeconn;
--m_curconn;
rest.post(); //信号量+1
Lock.unlock();
}
Pool* Pool::getInstance(){
static Pool conn; //全类共享
return &conn;
}
RAIIPool::RAIIPool(MYSQL** conn ,Pool* pool_){
*conn = pool_->GetConn();
RAIIconn = *conn;
RAIIpool = pool_;
}
RAIIPool::~RAIIPool(){
RAIIpool->Destroy();
}
locker类实现:
class locker
{
public:
locker(){
if(pthread_mutex_init(&mtx, nullptr) != 0){
throw std::exception();
}
}
~locker(){
pthread_mutex_destroy(&mtx);
}
bool lock(){
return pthread_mutex_lock(&mtx) == 0;
}
bool unlock(){
return pthread_mutex_unlock(&mtx) == 0;
}
pthread_mutex_t* GetMtx(){ //获取一把锁
return &mtx;
}
private:
pthread_mutex_t mtx;
};
class sem
{
public:
sem(int num){
if(sem_init(&id, 0, num) != 0){ //线程共享
throw std::exception();
}
}
sem(){
if(sem_init(&id, 0, 0) != 0){
throw std::exception();
}
}
~sem(){
sem_destroy(&id);
}
bool wait(){
return sem_wait(&id) == 0;
}
bool post(){
return sem_post(&id) == 0;
}
private:
sem_t id;
};