基于C++實(shí)現(xiàn)Mysql數(shù)據(jù)庫(kù)連接池實(shí)例
項(xiàng)目技術(shù)點(diǎn)
- C語(yǔ)言進(jìn)行MYSQL數(shù)據(jù)庫(kù)編程
- 無(wú)鎖單例
- 基于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)庫(kù)實(shí)現(xiàn), 具備跨平臺(tái)的特性,省去了對(duì)于pthread庫(kù)的C++的封裝.更加針對(duì)于項(xiàng)目的核心邏輯上的思考和實(shí)現(xiàn). (主干到細(xì)節(jié))
- Makefile自動(dòng)化編譯
項(xiàng)目意義
高并發(fā)場(chǎng)景下, 頻繁創(chuàng)建, 銷(xiāo)毀連接帶來(lái)的性能損耗
三次握手,連接認(rèn)證(身份權(quán)限認(rèn)證),MySQL資源釋放, 四次揮手
每一次client 訪問(wèn) Mysql server都需要進(jìn)行上述操作. 上述這些操作是固定的流程. 真正的sql語(yǔ)句執(zhí)行操作才是我們無(wú)法逃脫的, 所以上述這些我們完全可以提前創(chuàng)建出來(lái),然后進(jìn)行不斷的復(fù)用connections. 實(shí)現(xiàn)mysql server訪問(wèn)的性能提升.
思考: 提前創(chuàng)建好的 connetions 數(shù)目是否是越多越好?
當(dāng)然是不可能,因?yàn)槊恳粋€(gè)connection都是需要占據(jù)一定的系統(tǒng)資源的, 創(chuàng)建過(guò)多的connection 會(huì)導(dǎo)致服務(wù)器資源緊張. 起碼per connection per socketfd (套接字資源)
思考: connections 數(shù)目設(shè)計(jì)?
上下限限制數(shù)目. initSize控制下限. maxSize控制連接上限 (一般是系統(tǒng)的最大mysql connetions num)
多余connection最長(zhǎng)閑置時(shí)間限制: maxIdleTime (及時(shí)釋放閑置連接)
資源緊張, 并發(fā)訪問(wèn)量高. 沒(méi)有連接可用 :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); //查詢(xún)操作, 返回查詢(xún)結(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)視銷(xiāo)毀空閑線程任務(wù)
項(xiàng)目復(fù)雜接口細(xì)節(jié)刨析
getConnection()
/* 從連接池中獲取一條連接. 相當(dāng)于是消費(fèi)者 消費(fèi)前提, _connectionQue中有貨, 所以無(wú)貨期間需要進(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中無(wú)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)控銷(xiāo)毀哪些長(zhǎng)期空閑的connection, 避免對(duì)于空閑資源的無(wú)端占用浪費(fèi). 每一次休眠一個(gè) _maxIdleTime 就出來(lái) 檢查, 定期輪詢(xún)檢查空閑麗連接進(jìn)行銷(xiāo)毀 */ 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ì)頭的連接沒(méi)有超過(guò)_maxIdleTime,其它連接肯定沒(méi)有 } } } }
到此這篇關(guān)于基于C++實(shí)現(xiàn)Mysql數(shù)據(jù)庫(kù)連接池實(shí)例的文章就介紹到這了,更多相關(guān)C++數(shù)據(jù)庫(kù)連接池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql 批量更新與批量更新多條記錄的不同值實(shí)現(xiàn)方法
在mysql中批量更新我們可能使用update,replace into來(lái)操作,下面小編來(lái)給各位同學(xué)詳細(xì)介紹mysql 批量更新與性能吧2013-10-10MySQL學(xué)習(xí)之基礎(chǔ)命令實(shí)操總結(jié)
MySQL 是最流行的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),在WEB應(yīng)用方面MySQL是最好的。本文將為大家詳細(xì)介紹一些MySQL的基礎(chǔ)命令,需要的可以參考一下2022-03-03mysql 添加索引 mysql 如何創(chuàng)建索引
本文將介紹mysql 如何創(chuàng)建索引,需要的朋友可以參考下2012-11-11MySql中 is Null段判斷無(wú)效和IFNULL()失效的解決方案
這篇文章主要介紹了MySql中 is Null段判斷無(wú)效和IFNULL()失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Mysql以u(píng)tf8存儲(chǔ)gbk輸出的實(shí)現(xiàn)方法提供
Mysql以u(píng)tf8存儲(chǔ)gbk輸出的實(shí)現(xiàn)方法提供...2007-11-11Mysql數(shù)據(jù)庫(kù)表定期備份的實(shí)現(xiàn)詳解
這篇文章主要介紹了Mysql數(shù)據(jù)庫(kù)表定期備份的實(shí)現(xiàn)詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03MySQL中常見(jiàn)的八種SQL錯(cuò)誤用法示例
這篇文章主要給大家介紹了關(guān)于MySQL中常見(jiàn)的八種SQL錯(cuò)誤用法示例的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08