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

70次阅读
没有评论

共计 6707 个字符,预计需要花费 17 分钟才能阅读完成。

行业资讯    
数据库    
基于 MysqlConnector/C++ 的数据库连接池的实现是怎样的

基于 MysqlConnector/C++ 的数据库连接池的实现是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

1. 连接池的介绍:

1.1 应用背景:

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

1.2 技术思想:

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

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

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

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

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

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

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

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

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

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

2. 编程实现:

头文件(connection_pool.h):

[html] view
plaincopy

 /* 

 *File: connection_pool.h 

 *Author: csc 

 */ 

#ifndef_CONNECTION_POOL_H 

#define _CONNECTION_POOL_H 

#include mysql_connection.h

#include mysql_driver.h

#include cppconn/exception.h

#include cppconn/driver.h

#include cppconn/connection.h

#include cppconn/resultset.h

#include cppconn/prepared_statement.h

#include cppconn/statement.h

#include pthread.h

#include list

usingnamespace std; 

usingnamespace sql; 

classConnPool{ 

private: 

intcurSize;// 当前已建立的数据库连接数量  

intmaxSize;// 连接池中定义的最大数据库连接数  

stringusername; 

stringpassword; 

stringurl; 

list Connection* connList;// 连接池的容器队列  

pthread_mutex_tlock;// 线程锁  

staticConnPool *connPool; 

Driver*driver; 

Connection*CreateConnection();// 创建一个连接  

voidInitConnection(int iInitialSize);// 初始化数据库连接池  

voidDestoryConnection(Connection *conn);// 销毁数据库连接对象  

voidDestoryConnPool();// 销毁数据库连接池  

ConnPool(stringurl,string user,string password,int maxSize);// 构造方法  

public: 

~ConnPool(); 

Connection*GetConnection();// 获得数据库连接  

voidReleaseConnection(Connection *conn);// 将数据库连接放回到连接池的容器中  

staticConnPool *GetInstance();// 获取数据库连接池对象  

}; 

#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

#include stdexcept

#include exception

#include stdio.h

#include connection_pool.h

usingnamespace std; 

usingnamespace sql; 

ConnPool*ConnPool::connPool=NULL; 

// 连接池的构造函数

ConnPool::ConnPool(stringurl, string userName,string password, int maxSize) 

 this- maxSize=maxSize; 

 this- curSize=0; 

 this- username=userName; 

 this- password=password; 

 this- url=url; 

 try{ 

 this- driver=sql::mysql::get_driver_instance(); 

 } 

 catch(sql::SQLException e) 

 { 

 perror(驱动连接出错;\n); 

 } 

 catch(std::runtime_error e) 

 { 

 perror(运行出错了 \n); 

 } 

 this- InitConnection(maxSize/2); 

// 获取连接池对象,单例模式

ConnPool*ConnPool::GetInstance(){ 

 if(connPool==NULL) 

 { 

 connPool=newConnPool(tcp://127.0.0.1:3306 , root , root ,50); 

 } 

 returnconnPool; 

// 初始化连接池,创建最大连接数的一半连接数量

voidConnPool::InitConnection(int iInitialSize) 

 Connection*conn; 

 pthread_mutex_lock(lock); 

 for(inti=0;i iInitialSize;i++) 

 { 

 conn=this- CreateConnection(); 

 if(conn){ 

 connList.push_back(conn); 

 ++(this- curSize); 

 } 

 else

 { 

 perror(创建 CONNECTION 出错); 

 } 

 } 

 pthread_mutex_unlock(lock); 

// 创建连接, 返回一个 Connection

Connection*ConnPool::CreateConnection(){ 

 Connection*conn; 

 try{ 

 conn=driver- connect(this- url,this- username,this- password);// 建立连接

 returnconn; 

 } 

 catch(sql::SQLException e) 

 { 

 perror(创建连接出错); 

 returnNULL; 

 } 

 catch(std::runtime_error e) 

 { 

 perror(运行时出错); 

 returnNULL; 

 } 

// 在连接池中获得一个连接

Connection*ConnPool::GetConnection(){ 

 Connection*con; 

 pthread_mutex_lock(lock); 

 if(connList.size() 0)// 连接池容器中还有连接

 { 

 con=connList.front();// 得到第一个连接

 connList.pop_front();// 移除第一个连接

 if(con- isClosed())// 如果连接已经被关闭,删除后重新建立一个

 { 

 deletecon; 

 con=this- CreateConnection(); 

 } 

 // 如果连接为空,则创建连接出错

 if(con==NULL) 

 { 

 –curSize; 

 } 

 pthread_mutex_unlock(lock); 

 returncon; 

 } 

 else{ 

 if(curSize  maxSize){// 还可以创建新的连接

 con= this- CreateConnection(); 

 if(con){ 

 ++curSize; 

 pthread_mutex_unlock(lock); 

 returncon; 

 } 

 else{ 

 pthread_mutex_unlock(lock); 

 returnNULL; 

 } 

 } 

 else{// 建立的连接数已经达到 maxSize

 pthread_mutex_unlock(lock); 

 returnNULL; 

 } 

 } 

// 回收数据库连接

voidConnPool::ReleaseConnection(sql::Connection * conn){ 

 if(conn){ 

 pthread_mutex_lock(lock); 

 connList.push_back(conn); 

 pthread_mutex_unlock(lock); 

 } 

// 连接池的析构函数

ConnPool::~ConnPool() 

 this- DestoryConnPool(); 

// 销毁连接池, 首先要先销毁连接池的中连接

voidConnPool::DestoryConnPool(){ 

 list Connection* ::iterator icon; 

 pthread_mutex_lock(lock); 

 for(icon=connList.begin();icon!=connList.end();++icon) 

 { 

 this- DestoryConnection(*icon);// 销毁连接池中的连接

 } 

 curSize=0; 

 connList.clear();// 清空连接池中的连接

 pthread_mutex_unlock(lock); 

// 销毁一个连接

voidConnPool::DestoryConnection(Connection* conn) 

 if(conn) 

 { 

 try{ 

 conn- close(); 

 } 

 catch(sql::SQLException e) 

 { 

 perror(e.what()); 

 } 

 catch(std::exception e) 

 { 

 perror(e.what()); 

 } 

 deleteconn; 

 } 

}  

[cpp]
view plaincopyprint?

/*

 * 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; 

关于基于 MysqlConnector/C++ 的数据库连接池的实现是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注丸趣 TV 行业资讯频道了解更多相关知识。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-17发表,共计6707字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)