生活随笔
收集整理的這篇文章主要介紹了
基于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
?/*?? ?????????*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*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{?? ????????????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?
?????????#include?"connection_pool.h" ????namespace?ConnectMySQL?{??????ConnPool?*connpool?=?ConnPool::GetInstance();????void?run()?{????????Connection?*con;??????Statement?*state;??????ResultSet?*result;??????????????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++的数据库连接池的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。