基于MysqlConnector/C++的数据库连接池的实现

来源:互联网 发布:8848 m3手机备份数据 编辑:程序博客网 时间:2024/06/09 14:13

1.连接池的介绍:

1.1应用背景:

一般的应用程序都会访问到数据库,在程序访问数据库的时候,每一次数据访问请求都必须经过下面几个步骤:建立数据库连接,打开数据库,对数据库中的数据进行操作,关闭数据库连接。而建立数据库连接和打开数据库是一件很消耗资源并且费时的工作,如果在系统中很频繁的发生这种数据库连接,必然会影响到系统的性能,甚至会导致系统的崩溃。

1.2技术思想:

系统初始化阶段,建立一定数量的数据库连接对象(Connection),并将其存储在连接池中定义的容器中。当有数据库访问请求时,就从连接池中的这个容器中拿出一个连接;当容器中的连接已经用完,并且还没有达到系统定义的最大连接数时,可以再创建一个新的连接当当前使用的连接数达到最大连接数时,就要等待其他访问请求将连接放回容器后才能使用。当使用完连接的时候,必须将连接放回容器中,这样不同的数据库访问请求就可以共享这些连接,通过重复使用这些已经建立的数据库连接,可以解决上节中说到的频繁建立连接的缺点,从而提高了系统的性能。

经过上述描述,我们可以归纳出数据库连接池的主要操作:

(1)首先建立一个数据库连接池对象

(2)初始化一定数量的数据库连接,放入连接池对象的容器中

(3)当有数据库访问请求时,直接从连接池的容器中得到一个连接,这里出现三种情况:

(a)当容器中的还有连接时,则返回给数据库访问请求者一个连接

(b)当容器中没有连接时,并且当前建立的连接数没有达到系统定义的最大连接数,则创建一个新的数据库连接。

(c)当容器中的没有连接并且当前建立的连接数达到系统定义的最大连接数,则当前访问数据库请求就要等待其他访问请求释放连接。

(4)当数据库访问完成后,应该将连接放回连接池的容器中。

(5)当服务停止时,需要先释放数据库连接池中的所有数据库连接,然后释放数据库连接对象。

2.编程实现:

头文件(connection_pool.h)

[html] view plaincopy
  1.  /*  
  2.          *File: connection_pool.h  
  3.           *Author: csc  
  4.      */  
  5. #ifndef_CONNECTION_POOL_H  
  6. #define _CONNECTION_POOL_H  
  7. #include<mysql_connection.h>  
  8. #include<mysql_driver.h>  
  9. #include<cppconn/exception.h>  
  10. #include<cppconn/driver.h>  
  11. #include<cppconn/connection.h>  
  12. #include<cppconn/resultset.h>  
  13. #include<cppconn/prepared_statement.h>  
  14. #include<cppconn/statement.h>  
  15. #include<pthread.h>  
  16. #include<list>  
  17. usingnamespace std;  
  18. usingnamespace sql;  
  19.   
  20. classConnPool{  
  21. private:  
  22. intcurSize;//当前已建立的数据库连接数量  
  23. intmaxSize;//连接池中定义的最大数据库连接数  
  24. stringusername;  
  25. stringpassword;  
  26. stringurl;  
  27. list<Connection*>connList;//连接池的容器队列  
  28. pthread_mutex_tlock;//线程锁  
  29. staticConnPool *connPool;  
  30. Driver*driver;  
  31.   
  32. Connection*CreateConnection();//创建一个连接  
  33. voidInitConnection(int iInitialSize);//初始化数据库连接池  
  34. voidDestoryConnection(Connection *conn);//销毁数据库连接对象  
  35. voidDestoryConnPool();//销毁数据库连接池  
  36. ConnPool(stringurl,string user,string password,int maxSize);//构造方法  
  37. public:  
  38. ~ConnPool();  
  39. Connection*GetConnection();//获得数据库连接  
  40. voidReleaseConnection(Connection *conn);//将数据库连接放回到连接池的容器中  
  41. staticConnPool *GetInstance();//获取数据库连接池对象  
  42. };  
  43. #endif  /*_CONNECTION_POOL_H */  


头文件中定义了一个容器connList,里面存放了很多个未使用的连接在对容器内的连接进行操作的时候,需要加锁保证程序的安全性,所以头文件中定义了一个lock,通过使用lock保证了同一时间只有一个线程对容器进行操作。

连接池类要统一管理整个应用程序中的连接,所以在整个系统中只需要维护一个连接池对象,试想:如果系统中定义了多个连接池对象,那么每一个对象都可以建立maxSize个连接,这样就失去了创建连接池的初衷,破环了通过连接池统一管理系统中连接的思想。所以这里使用单例模式编写连接池类,单例模式确保一个类只有一个实例,自己进行实例化并且向整个系统提供这个实例。在头文件中,我们定义了一个静态的连接池对象connPool连接池类提供一个静态的公共方法GetInstance(),外部程序通过调用这个方法来获得连接池对象。并且将连接池类的构造函数定义为私有的,外部的应用程序不能够通过new来实例化连接池类,只能通过GetInstance()方法获得连接池对象;在GetInstance()方法中需要判断连接池类中定义的connPool是否为NULL,若为NULL则调用私有构造函数实例化connPool,若不为空,则直接返回connPool。这样就实现了连接池类的单例模式,从而保证了系统运行过程中只建立一个连接池类的实例对象。

在实例化连接池类的对象时,要对连接池做一些初始化的操作,即建立一定数量的数据库连接。程序中通过InitConnection(intiInitialSize)方法对连接池进行初始化,创建iInitialSize个连接,并且将这些连接放在连接池中的容器connList中,每新建一个连接,curSize就加1。当有数据库访问请求时,需要从连接池中获取一个连接,通过GetConnection()方法实现:首先判断容器中是否还有连接,如果有,则拿出容器中的第一个连接,并且将该连接移出容器;获得的连接要进行判断,如果连接已经关闭,则回收该连接的内存空间,并且重新创建一个连接;然后判断新创建的连接是否为空,如果为空,则说明当前已经建立连接的数量并不是curSize个,而是(curSize-1)(应该除去这个空连接)。如果容器中已经没有连接了,则要判断当前的curSize值是否已经达到规定的maxSize,如果没有小于maxSize,将建立一个新的连接(++curSize)。如果超过maxSize则等待其他数据库访问请求释放数据库连接。

连接使用完以后,需要将连接放回连接池中,通过ReleaseConnection(sql::Connection* conn)方法实现,它的实现非常简单,就是将传进来的connection连接添加到连接池的容器中。

当需要回收连接池的内存空间时,需要先回收连接池中所有连接的内存空间,然后再释放连接池对象的内存空间。

实现数据库连接池主要的步骤就是上述这些,具体的代码实现如下所示:

[cpp] view plaincopy
  1. #include<stdexcept>  
  2. #include<exception>  
  3. #include<stdio.h>  
  4. #include"connection_pool.h"  
  5.   
  6. usingnamespace std;  
  7. usingnamespace sql;  
  8.   
  9. ConnPool*ConnPool::connPool=NULL;  
  10. //连接池的构造函数  
  11. ConnPool::ConnPool(stringurl, string userName,string password, int maxSize)  
  12. {  
  13.     this->maxSize=maxSize;  
  14.     this->curSize=0;  
  15.     this->username=userName;  
  16.     this->password=password;  
  17.     this->url=url;  
  18.     try{  
  19.         this->driver=sql::mysql::get_driver_instance();  
  20.     }  
  21.     catch(sql::SQLException&e)  
  22.     {  
  23.         perror("驱动连接出错;\n");  
  24.     }  
  25.     catch(std::runtime_error&e)  
  26.     {  
  27.         perror("运行出错了\n");  
  28.     }  
  29.     this->InitConnection(maxSize/2);  
  30. }  
  31. //获取连接池对象,单例模式  
  32. ConnPool*ConnPool::GetInstance(){  
  33.     if(connPool==NULL)  
  34.     {  
  35.         connPool=newConnPool("tcp://127.0.0.1:3306","root","root",50);  
  36.     }  
  37.     returnconnPool;  
  38. }  
  39. //初始化连接池,创建最大连接数的一半连接数量  
  40. voidConnPool::InitConnection(int iInitialSize)  
  41. {  
  42.     Connection*conn;  
  43.     pthread_mutex_lock(&lock);  
  44.     for(inti=0;i<iInitialSize;i++)  
  45.     {  
  46.         conn=this->CreateConnection();  
  47.         if(conn){  
  48.             connList.push_back(conn);  
  49.             ++(this->curSize);  
  50.         }  
  51.         else  
  52.         {  
  53.             perror("创建CONNECTION出错");  
  54.         }  
  55.     }  
  56.     pthread_mutex_unlock(&lock);  
  57. }  
  58. //创建连接,返回一个Connection  
  59. Connection*ConnPool::CreateConnection(){  
  60.     Connection*conn;  
  61.     try{  
  62.         conn=driver->connect(this->url,this->username,this->password);//建立连接  
  63.         returnconn;  
  64.     }  
  65.     catch(sql::SQLException&e)  
  66.     {  
  67.         perror("创建连接出错");  
  68.         returnNULL;  
  69.     }  
  70.     catch(std::runtime_error&e)  
  71.     {  
  72.         perror("运行时出错");  
  73.         returnNULL;  
  74.     }  
  75. }  
  76. //在连接池中获得一个连接  
  77. Connection*ConnPool::GetConnection(){  
  78.     Connection*con;  
  79.     pthread_mutex_lock(&lock);  
  80.     if(connList.size()>0)//连接池容器中还有连接  
  81.     {  
  82.         con=connList.front();//得到第一个连接  
  83.         connList.pop_front();//移除第一个连接  
  84.         if(con->isClosed())//如果连接已经被关闭,删除后重新建立一个  
  85.         {  
  86.             deletecon;  
  87.             con=this->CreateConnection();  
  88.         }  
  89.         //如果连接为空,则创建连接出错  
  90.         if(con==NULL)  
  91.         {  
  92.             --curSize;  
  93.         }  
  94.         pthread_mutex_unlock(&lock);  
  95.         returncon;  
  96.     }  
  97.     else{  
  98.         if(curSize< maxSize){//还可以创建新的连接  
  99.             con= this->CreateConnection();  
  100.             if(con){  
  101.                 ++curSize;  
  102.                 pthread_mutex_unlock(&lock);  
  103.                 returncon;  
  104.             }  
  105.             else{  
  106.                 pthread_mutex_unlock(&lock);  
  107.                 returnNULL;  
  108.             }  
  109.         }  
  110.         else{//建立的连接数已经达到maxSize  
  111.             pthread_mutex_unlock(&lock);  
  112.             returnNULL;  
  113.         }  
  114.     }  
  115. }  
  116. //回收数据库连接  
  117. voidConnPool::ReleaseConnection(sql::Connection * conn){  
  118.     if(conn){  
  119.         pthread_mutex_lock(&lock);  
  120.         connList.push_back(conn);  
  121.         pthread_mutex_unlock(&lock);  
  122.     }  
  123. }  
  124. //连接池的析构函数  
  125. ConnPool::~ConnPool()  
  126. {  
  127.     this->DestoryConnPool();  
  128. }  
  129. //销毁连接池,首先要先销毁连接池的中连接  
  130. voidConnPool::DestoryConnPool(){  
  131.     list<Connection*>::iterator icon;  
  132.     pthread_mutex_lock(&lock);  
  133.     for(icon=connList.begin();icon!=connList.end();++icon)  
  134.     {  
  135.         this->DestoryConnection(*icon);//销毁连接池中的连接  
  136.     }  
  137.     curSize=0;  
  138.     connList.clear();//清空连接池中的连接  
  139.     pthread_mutex_unlock(&lock);  
  140. }  
  141. //销毁一个连接  
  142. voidConnPool::DestoryConnection(Connection* conn)  
  143. {  
  144.     if(conn)  
  145.     {  
  146.         try{  
  147.             conn->close();  
  148.         }  
  149.         catch(sql::SQLException&e)  
  150.         {  
  151.             perror(e.what());  
  152.         }  
  153.         catch(std::exception&e)  
  154.         {  
  155.             perror(e.what());  
  156.         }  
  157.         deleteconn;  
  158.     }  
  159. }  

/* * main.cpp * *  Created on: 2013-3-26 *      Author: holy */#include "connection_pool.h"namespace ConnectMySQL {//初始化连接池ConnPool *connpool = ConnPool::GetInstance();void run() {Connection *con;Statement *state;ResultSet *result;// 从连接池中获取mysql连接con = connpool->GetConnection();state = con->createStatement();state->execute("use holy");// 查询result = state->executeQuery("select * from student where id < 1002");// 输出查询while (result->next()) {int id = result->getInt("id");string name = result->getString("name");cout << id << " : " << name << endl;}delete state;connpool->ReleaseConnection(con);}}int main(int argc, char* argv[]) {ConnectMySQL::run();return 0;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 露肩连体裤穿着卡裆怎么办 魅族手机恋与制作人换诺基亚怎么办 蚊子叮咬后擦风油精了红肿怎么办 机动车已转让没过户出了事情怎么办 签好的合同如果甲方违约怎么办? 饭店没签合同辞职不给工资怎么办 两家为了带孩子闹翻了怎么办啊? 抵押后租赁的房屋被法院拍卖怎么办 房子买20年了没有过户怎么办 二手车没过户行驶证丢了怎么办 买的二手车行驶证丢了怎么办 在京东仓库做事把东西损坏了怎么办 微信显示该账号登陆环境异常怎么办 干洗店把衣服洗坏了怎么办 千牛上怎么改淘宝密码忘记了怎么办 公司收了代理商押金到期不退怎么办 淘宝显示签收但是我没收到货怎么办 淘宝东西没收到显示签收了怎么办 开拼多多店铺的密码忘了怎么办 拼多多密码跟店铺名忘了怎么办 闲鱼上卖出的宝贝被调包了怎么办 上传身份证照片说格式错误该怎么办 我给厂里打的款不给发货怎么办 净值接近不定期份额折算阀值怎么办 有锁电信4g掉了怎么办 在电脑中找不到想作废的发票怎么办 科目三补考费发票丢了怎么办 母婴店飞鹤奶粉突然厂家撤货怎么办 澳门买的保健品感觉是假的怎么办 淘宝买东西提交需求时卡死了怎么办 天猫精灵显示为离线状态怎么办 退货多被淘宝店铺拉入黑名单怎么办 天猫订单3天不发货怎么办 新开的厨卫店越来越没生意怎么办 淘宝积分不够领不到购物津贴怎么办 穿越火线精英集结号积分不足怎么办 天猫购物津贴领多了怎么办 车贷逾期车被开走还不清全款怎么办 孩子特别懒不爱动又胖怎么办 微信的聊天记录被限制了怎么办 门面租金交了一年对方不租了怎么办