基于C++實(shí)現(xiàn)Mysql數(shù)據(jù)庫連接池實(shí)例
項(xiàng)目技術(shù)點(diǎn)
- C語言進(jìn)行MYSQL數(shù)據(jù)庫編程
- 無鎖單例
- 基于STL隊(duì)列加C++11新特性保證線程安全實(shí)現(xiàn)的生產(chǎn)者消費(fèi)者模型
- C++11多線程編程 (線程間同步與互斥)
- 基于CAS的原子整形
- lambda表達(dá)式
- shared_ptr智能指針管理Connection*指針對(duì)象
- 基于C++11標(biāo)準(zhǔn)庫實(shí)現(xiàn), 具備跨平臺(tái)的特性,省去了對(duì)于pthread庫的C++的封裝.更加針對(duì)于項(xiàng)目的核心邏輯上的思考和實(shí)現(xiàn). (主干到細(xì)節(jié))
- Makefile自動(dòng)化編譯
項(xiàng)目意義
高并發(fā)場景下, 頻繁創(chuàng)建, 銷毀連接帶來的性能損耗
三次握手,連接認(rèn)證(身份權(quán)限認(rèn)證),MySQL資源釋放, 四次揮手
每一次client 訪問 Mysql server都需要進(jìn)行上述操作. 上述這些操作是固定的流程. 真正的sql語句執(zhí)行操作才是我們無法逃脫的, 所以上述這些我們完全可以提前創(chuàng)建出來,然后進(jìn)行不斷的復(fù)用connections. 實(shí)現(xiàn)mysql server訪問的性能提升.
思考: 提前創(chuàng)建好的 connetions 數(shù)目是否是越多越好?
當(dāng)然是不可能,因?yàn)槊恳粋€(gè)connection都是需要占據(jù)一定的系統(tǒng)資源的, 創(chuàng)建過多的connection 會(huì)導(dǎo)致服務(wù)器資源緊張. 起碼per connection per socketfd (套接字資源)
思考: connections 數(shù)目設(shè)計(jì)?
上下限限制數(shù)目. initSize控制下限. maxSize控制連接上限 (一般是系統(tǒng)的最大mysql connetions num)
多余connection最長閑置時(shí)間限制: maxIdleTime (及時(shí)釋放閑置連接)
資源緊張, 并發(fā)訪問量高. 沒有連接可用 :connectionTimeout (return error, 獲取連接超時(shí)時(shí)間)
項(xiàng)目實(shí)現(xiàn)
Connection設(shè)計(jì)
數(shù)據(jù)成員
MYSQL* _conn; //連接句柄 clock_t _startTime; //連接起始空閑時(shí)間
操作接口
Connection(); //構(gòu)造 init Connection ~Connection(); //析構(gòu) destroy connection bool connect(ip, port, username, password, dbname); //連接操作, 返回連接結(jié)果 bool update(sql); //表更新操作, 返回更新結(jié)果 MYSQL_RES* query(sql); //查詢操作, 返回查詢結(jié)果 void refreshStartTime(); //刷新連接起始空閑時(shí)間 clock_t getAliveTime(); //獲取連接空閑時(shí)間
ConnectionPool設(shè)計(jì)
數(shù)據(jù)成員
//連接登錄信息 string _ip; unsigned short _port; string _username; string _password; string _dbname; //連接數(shù)量等配置信息 int _initSize; int _maxSize; int _maxIdleTime; int _connectionTimeout; //連接存儲(chǔ)信息,以及保證線程安全 queue<Connection*> _connectionQue; mutex _queueLock; condition_variable _cond; atomic_int _connectionCnt;
操作接口
ConnectionPool(); //構(gòu)造 init pool, 加載配置, 初始連接, 啟動(dòng)線程 static ConnectionPool* getConnectionPool();//獲取單例 shared_ptr<Connection> getConnection(); //獲取連接 int _loadConfigFile(string& filename); //加載解析配置信息 void produceConnectionTask(); //生產(chǎn)連接任務(wù) void scannerConnetionTask(); //掃描監(jiān)視銷毀空閑線程任務(wù)
項(xiàng)目復(fù)雜接口細(xì)節(jié)刨析
getConnection()
/*
從連接池中獲取一條連接. 相當(dāng)于是消費(fèi)者
消費(fèi)前提, _connectionQue中有貨, 所以無貨期間需要進(jìn)行阻塞休眠等待.
等待也不能一直等待. 存在連接超時(shí)時(shí)間,
waittime >= _connectionTimeout then output << error.
*/
shared_ptr<Connection> getConnection() {
unique_lock<mutex> auto_lock(_queueLock);//定義智能鎖
while (_connectionQue.empty()) {
if (cv_status::timeout == _cond.wait_for(auto_lock, chrono::milliseconds(_connectionTimeout))) { //達(dá)到連接超時(shí)時(shí)間
if (_connectionQue.empty()) {
//LOG DEBUG INFO
cerr << "獲取連接超時(shí)" << endl;
return nullptr;
}
}
}
//定義shared_ptr<Connection> 自定義del函數(shù), 而非直接調(diào)用~T()
shared_ptr<Connection> sp(_connectionQue.front(), [&](Connection* pconn){
unique_lock<mutex> auto_lock(_queueLock);
pconn->refreshStartTime(); //刷新連接起始空閑時(shí)間
_connectionQue.push(pconn);
});
_connectionQue.pop();
_cond.notify_all(); //彈出任務(wù), queue maybe empty notify produce
return sp;
}produceConnectionTask()
/*
生產(chǎn)者線程任務(wù). 在_connectionQue中無connetion
&& _connectionCnt < _maxSize 時(shí)候 及時(shí)創(chuàng)建連接填充_connectionQue。
*/
void produceConnectionTask() {
for (;;) {
unique_lock<mutex> auto_lock(_queueLock);
while (!_connectionQue.empty()) {
_cond.wait(auto_lock);
}
if (_connectionCnt < _maxSize) {
Connection* pconn = new Connection();
pconn->connet(_ip, _port, _username, _password, _dbname);
pconn->refreshStartTime();
_connectionQue.push(pconn);
_connectionCnt++;
}
_cond.notify_all(); //通知消費(fèi)
}
}
?scannerConnetionTask()
/*
不停的掃描所有的connection, 從頭到尾的掃描,
監(jiān)控銷毀哪些長期空閑的connection, 避免對(duì)于空閑資源的無端占用浪費(fèi).
每一次休眠一個(gè) _maxIdleTime 就出來 檢查, 定期輪詢檢查空閑麗連接進(jìn)行銷毀
*/
void scannerConnectionTask() {
for (;;) {
//休眠maxIdleTime
this_thread::sleep_for(chrono::seconds(_maxIdleTime));
unique_lock<mutex> auto_lock(_queueLock);
while (_connectionCnt > _initSize)
{
Connection *p = _connectionQue.front();
if (p->getAliveeTime()/SECONDS_PER_SEC >= _maxIdleTime)
{
_connectionQue.pop();
_connectionCnt--;
delete p; // 調(diào)用~Connection()釋放連接
}
else
{
break; // 隊(duì)頭的連接沒有超過_maxIdleTime,其它連接肯定沒有
}
}
}
}到此這篇關(guān)于基于C++實(shí)現(xiàn)Mysql數(shù)據(jù)庫連接池實(shí)例的文章就介紹到這了,更多相關(guān)C++數(shù)據(jù)庫連接池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL中TEXT類型存儲(chǔ)極限與實(shí)踐案例
本文解析MySQL TEXT類型存儲(chǔ)極限及工程實(shí)踐,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-10-10
MySQL數(shù)據(jù)庫子查詢語法規(guī)則詳解
子查詢是在查詢語句里面再嵌套一個(gè)查詢,這是因?yàn)槲覀冊谔崛?shù)據(jù)的時(shí)候有很多不知道的數(shù)據(jù)產(chǎn)生了依賴關(guān)系。本文為大家總結(jié)了一下MySQL數(shù)據(jù)庫子查詢語法規(guī)則,感興趣的可以了解一下2022-08-08
Mysql中l(wèi)eft join、right join和inner join(join)的區(qū)
本文介紹了leftjoin、rightjoin和innerjoin的區(qū)別和使用場景,以圖文形式輔以實(shí)例講解,幫助讀者清晰理解三種SQL連接查詢的特點(diǎn)和應(yīng)用2024-10-10
Mysql 忘記root密碼和修改root密碼的解決方法(小結(jié))
這篇文章主要介紹了Mysql 忘記root密碼和修改root密碼的解決方法(小結(jié)),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12
mysql_fetch_row()與mysql_fetch_array()的使用介紹
本篇文章是對(duì)mysql_fetch_row()與mysql_fetch_array()的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06

