文档章节

Mysql Connector(C++)的数据库连接池的实现

清风伴月
 清风伴月
发布于 2017/04/13 17:25
字数 2260
阅读 79
收藏 0

1.连接池的介绍:

1.1应用背景:

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

1.2技术思想:

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

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

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

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

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

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

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

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

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

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

2.编程实现:

头文件(connection_pool.h):

 

  1.  /*  
  2.          *File: connection_pool.h  
  3.        
  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连接添加到连接池的容器中。

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

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

 

  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. }  

© 著作权归作者所有

上一篇: HashMap
下一篇: socket(套接字)
清风伴月
粉丝 1
博文 129
码字总数 255659
作品 0
海淀
程序员
私信 提问
MySQL Connector/C++ 1.1 发布

MySQL Connector/C++ 是 C/C++ 用来连接到 MySQL 数据库的客户端开发包。 1.1 版本改进内容请看 Change History 更多关于 Connector/C++ 的文档:http://dev.mysql.com/doc/refman/5.1/en/co...

红薯
2010/09/14
999
0
MySQL Connector/C++ 1.1.4 发布

MySQL Connector/ODBC 是 MySQL 数据库的官方C++驱动程序。 MySQL Connector/C++ 1.1.4 发布,此版本的二进制版本需要使用 Boost 1.54.0 编译。 新增的特性和改进 Connector/C++ 支持以下的连...

oschina
2014/08/01
3.6K
5
坑爹的MYSQL CONNECTOR C++

近来要开发C++连接mysql的一个模块,首先在官网上下了一个Connector C++ 1.1.0,发现竟然要用到boost库...为了一个连接组件,竟然要安装整个boost,而且看了下Connector的源代码,发现竟然只...

xinzaibing
2012/07/24
3.7K
5
支持 LINUX/WIN32 平台的网络通讯及服务器框架

acl 框架库是一个 C 库,主要包含:服务器开发框架、同步/异步网络通讯、常用数据结构、进程池/线程池、流式 xml/json 解析器、http/ping 应用协议等内容; acl_cpp 是基于 acl 库的 C++ 库,...

郑树新
2012/06/03
38
0
MySQL Connector/C++ 1.1.3 发布

MySQL Connector/C++ 1.1.3 发布,很小的改动版本,改动记录请看这里。 MySQL Connector/ODBC 是 MySQL 数据库的官方C++驱动程序。

oschina
2013/04/08
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周一乱弹 —— 年迈渔夫遭黑帮袭抢

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享Elvis Presley的单曲《White Christmas》: 《White Christmas》- Elvis Presley 手机党少年们想听歌,请使劲...

小小编辑
今天
1K
18
CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
5
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
8
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
12
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部