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

From: http://blog.csdn.net/educast/article/details/14164097

 

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

[cpp] view plaincopyprint?
  1. /* 
  2.  * main.cpp 
  3.  * 
  4.  *  Created on: 2013-3-26 
  5.  *      Author: holy 
  6.  */  
  7.   
  8. #include "connection_pool.h"   
  9.   
  10. namespace ConnectMySQL {  
  11.   
  12. //初始化连接池   
  13. ConnPool *connpool = ConnPool::GetInstance();  
  14.   
  15. void run() {  
  16.   
  17.     Connection *con;  
  18.     Statement *state;  
  19.     ResultSet *result;  
  20.   
  21.     // 从连接池中获取mysql连接   
  22.     con = connpool->GetConnection();  
  23.   
  24.     state = con->createStatement();  
  25.     state->execute("use holy");  
  26.   
  27.     // 查询   
  28.     result = state->executeQuery("select * from student where id < 1002");  
  29.   
  30.     // 输出查询   
  31.     while (result->next()) {  
  32.         int id = result->getInt("id");  
  33.         string name = result->getString("name");  
  34.         cout << id << " : " << name << endl;  
  35.     }  
  36.     delete state;  
  37.     connpool->ReleaseConnection(con);  
  38. }  
  39. }  
  40.   
  41. int main(int argc, char* argv[]) {  
  42.     ConnectMySQL::run();  
  43.     return 0;  
  44. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403577.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【javascript】不刷新页面,实时显示当前时间

这里起主要作用的是setTimeout这个函数。 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"><head>…

PCL Show Point Cloud 显示点云

在使用PCL库的时候&#xff0c;经常需要显示点云&#xff0c;可以用下面这段代码&#xff1a; #include <pcl/visualization/cloud_viewer.h>pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; pcl::visualization::CloudViewer viewer ("Viewer"); viewer…

css字体自定义,bootstrap自定义字体

<style type"text/css">font-face{font-family:myFont;src:url(/bootstrap-3.3.7-dist/fonts/shishangjianti.ttf);}body{font-family: myFont !important;}</style> .ttf的文件路径根据文件位置定义

cmd连接mysql的方法详解

From: http://www.jb51.net/article/38059.htm 本篇文章是对cmd连接mysql的方法进行了详细的分析介绍&#xff0c;需要的朋友参考下连接&#xff1a;mysql -h主机地址 -u用户名 &#xff0d;p用户密码 &#xff08;注:u与root可以不用加空格&#xff0c;其它也一样&#xff09;…

c/c++多参数的问题

C/C语言有一个不同于其它语言的特性&#xff0c;即其支持可变参数&#xff0c;典型的函数如printf、scanf等可以接受数量不定的参数。如&#xff1a; printf ( "I love you" ); printf ( "%d", a ); printf ( "%d,%d", a, b );第一、二、三个pr…

JS node 后端签名前端文件直传ali-oss解决方案

1&#xff1a;首先打开跨域 上面搞好了开始写代码 html <input type"file" id"upload" onchange"uploadfile()"> js function uploadfile() {var file document.getElementById(upload).files[0]$.ajax({url: /policy,data: ,type: get…

在linux上获得线程id的方法

From: http://www.linuxidc.com/Linux/2014-01/94723.htm 我使用了第二种方法&#xff0c;很方便&#xff1a; #define gettid() syscall(__NR_gettid) 用到的地方 gettid() 在linux2.4版本后&#xff0c;linux使用了NPTL作为自己的线程库&#xff0c;为了兼容POSIX标准&a…

【MCAL】TC397+EB-treso之MCU配置实战 - 芯片时钟

本篇文章介绍了在TC397平台使用EB-treso对MCU驱动模块进行配置的实战过程&#xff0c;主要介绍了后续基本每个外设模块都要涉及的芯片时钟部分&#xff0c;帮助读者了解TC397芯片的时钟树结构&#xff0c;在后续计算配置不同外设模块诸如通信速率&#xff0c;定时器周期等&…

html引入UI库vant

vant地址 注意html中不支持单标签元素 元素标签必须是闭合标签 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta nam…

nunjucks渲染富文本解析错误输出字符串而不是元素

今天遇到个坑&#xff0c;nunjucks 的插入变量{{}}输出的是字符串&#xff0c;而我用富文本编辑器插入数据库的是字符串&#xff0c;它不解析成元素(html),怎么办&#xff1f; 用什么方法引入它能成html&#xff1f; 网上查&#xff0c;没这个资料 因为以前用过EJS输出过字符…

ubuntu下安装、卸载软件

2019独角兽企业重金招聘Python工程师标准>>> 安装&#xff1a;(1) apt-get install name 卸载&#xff1a;(1) apt-get remove name 卸载并清除配置&#xff1a;(1) apt-get remove --purge name 更新信息库&#xff1a;apt-get update 系统升级&#xff1a;apt-get…

英文版Ubuntu 安装中文输入法

一、安装语言包 &#xff08;系统默认会安装中文简体语言包&#xff09; System Settings-->Language Support-->Install/Remove Languages 二、安装IBUS框架 sudo apt-get install ibus ibus-clutter ibus-gtk ibus-gtk3 ibus-qt4 三、安装中文引擎 Ibus 拼音&#xff1…

Linux获取线程id的方法学习

From: http://www.linuxidc.com/Linux/2014-01/94723.htm 最近一直在想&#xff1a; 如何确认两段代码是不是在同一个线程中执行的呢&#xff1f; 通过查看资料&#xff0c;发现一种比较简单的方法就是在代码中使用printf将当前线程的id打印出来。 而这也分成两种情况&#x…

console使用

console.log用于控制台打印&#xff1b;但除此之外console还有很多用处 1.分组打印console.group(分组打印1-2)console.log(1);console.log(2);console.groupEnd()console.group(分组打印3-4)console.log(3);console.log(4);console.group(俄罗斯套娃)console.log(5);console.…

Linux平台上搭建apache+tomcat负载均衡集群

传统的Java Web项目是通过tomcat来运行和发布的。但在实际的企业应用环境中&#xff0c;采用单一的tomcat来维持项目的运行是不现实的。tomcat 处理能力低&#xff0c;效率低&#xff0c;承受并发小&#xff08;1000左右&#xff09;。当用户请求较少时&#xff0c;单一的tomca…

(转)C#中 DirectoryEntry组件应用实例

C#中 DirectoryEntry组件应用实例DirectoryEntry类封装Active Directory层次结构中的节点或对象&#xff0c;使用该类可以绑定到对象&#xff0c;或者读取和更新属性。图1所示为DirectoryEntry组件。DirectoryEntry组件1&#xff0e; 功能DirectoryEntry类封装Active Director…

小程序设置header cookie

代码片段 method: POST,url: config.service.balabala,data: this.data.balabala,header: { cookie: demobalabala;loginbalabala},success: function (data) {

【Linux学习】epoll详解

From: http://blog.csdn.net/xiajun07061225/article/details/9250579 什么是epoll epoll是什么&#xff1f;按照man手册的说法&#xff1a;是为处理大批量句柄而作了改进的poll。当然&#xff0c;这不是2.6内核才有的&#xff0c;它是在2.5.44内核中被引进的(epoll(4) is a …