共計 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 行業資訊頻道了解更多相關知識。