Server/王琨元/code/ConnectionPool.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
Server/王琨元/code/ConnectionPool.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
Server/王琨元/code/MysqlConn.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
Server/王琨元/code/MysqlConn.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
Server/ÍõçûÔª/code/ConnectionPool.cpp
@@ -1,95 +1,101 @@ #include "ConnectionPool.h" ConnectionPool::ConnectionPool() { if (!parseXmlFile()) #include <fstream> #include <iostream> #include <thread> ConnectionPool* ConnectionPool::getInstance() { static ConnectionPool connPool; return &connPool; } ConnectionPool::ConnectionPool() { // å è½½é ç½®æä»¶ if (!parseJsonFile()) { std::cout << "parseJsonFile is failed!" << std::endl; return; for (m_num = 0; m_num < m_minSize;) { bool flag = addConnection(); if (!flag) { return; } } // 妿å线ç¨çä»»å¡å½æ°æ¯ç±»çééæå½æ°ï¼æä»¬éè¦æå®ä»»å¡å½æ°çå°ååä»»å¡å½æ°çææè thread producer(&ConnectionPool::productConnection, this); // åå»ºè¿æ¥ thread recycler(&ConnectionPool::recycleConnection, this); // æ£æµå¹¶éæ¯è¿æ¥ // 线ç¨å离ï¼é²æ¢é»å¡ä¸»çº¿ç¨ for ( int i = 0 ; i < m_min_conn ; i++ ) { addConnection( ); } // å建ä¸ä¸ªçº¿ç¨ï¼å¯¹è¿æ¥æ°è¿è¡çæ§ ï¼è¿æ¥æ°ä¸è¶³å°±åç»§ç»å建 std::thread producer(&ConnectionPool::produce, this); // å¯¹è¿æ¥æ°è¿è¡çæ§ ï¼å¦ææå¤ªå¤ç©ºé²å¾çº¿ç¨ ï¼é£ä¹å°±å¯¹å ¶è¿è¡éæ¯ std::thread recycler( &ConnectionPool::recycle, this); // 线ç¨å离 producer.detach(); recycler.detach(); } ConnectionPool::~ConnectionPool() { while (!m_connections.empty()) { MysqlConn* conn = m_connections.front(); m_connections.pop(); delete conn; } } bool ConnectionPool::parseXmlFile() { TiXmlDocument xml("mysql.xml"); // å è½½æä»¶ bool res = xml.LoadFile(); if (!res) { return false; // æç¤º } // æ ¹ TiXmlElement* rootElement = xml.RootElement(); TiXmlElement* childElement = rootElement->FirstChildElement("mysql"); // 读åä¿¡æ¯ m_ip = childElement->FirstChildElement("ip")->GetText(); m_port = static_cast<unsigned short>(stoi(string(childElement->FirstChildElement("port")->GetText()))); m_user = childElement->FirstChildElement("username")->GetText(); m_passwd = childElement->FirstChildElement("password")->GetText(); m_dbName = childElement->FirstChildElement("dbName")->GetText(); m_minSize = static_cast<int>(stoi(string(childElement->FirstChildElement("minSize")->GetText()))); m_maxSize = static_cast<int>(stoi(string(childElement->FirstChildElement("maxSize")->GetText()))); m_maxIdleTime = static_cast<int>(stoi(string(childElement->FirstChildElement("maxIdleTime")->GetText()))); m_timeout = static_cast<int>(stoi(string(childElement->FirstChildElement("timeout")->GetText()))); return true; } bool ConnectionPool::addConnection() { MysqlConn* conn = new MysqlConn; bool res = conn->connect(m_user, m_passwd, m_dbName, m_ip, m_port); if (res) { // å·æ°ç©ºé²æ¶é´ conn->refreashAliveTime(); m_connections.push(conn); ++m_num; bool ConnectionPool::parseJsonFile() { std::ifstream ifs("dbconf.json"); Reader rd; Value root; rd.parse(ifs, root); if ( root.isObject( ) ) { m_ip = root["ip"].asString(); m_port = root["port"].asInt(); m_userName = root["userName"].asString(); m_passwd = root["password"].asString(); m_db = root["dbName"].asString(); m_min_conn = root["minSize"].asInt(); m_max_conn = root["maxSize"].asInt(); max_del_time = root["maxDleTime"].asInt(); m_timeout = root["timeout"].asInt(); return true; } else { return false; } void ConnectionPool::description() { std::cout << m_ip << ". " << m_userName << ". " << m_passwd << ". " << m_db << ". " << m_port << ". " << m_max_conn << ". " << m_min_conn << ". " << m_timeout << ". " << max_del_time << std::endl; } ConnectionPool::~ConnectionPool() { while (!m_connkQueue.empty()) { MysqlConn* conn = m_connkQueue.front(); m_connkQueue.pop(); delete conn; } } void ConnectionPool::addConnection() { MysqlConn* conn = new MysqlConn(); if ( !conn->connect( m_ip, m_userName, m_passwd, m_db, m_port ) ) { std::cout << "ConnectionPool connect to mysql is failed!" << std::endl; delete conn; return false; // æç¤º return; } conn->refreshActiveTime( ); m_connkQueue.push(conn); m_cond.notify_one(); // å¤éä¸ä¸ªçº¿ç¨ } void ConnectionPool::productConnection() { void ConnectionPool::produce(){ while (true) { unique_lock<mutex> lc(m_mutex); m_cond.wait(lc, [this]() {return m_connections.empty(); }); if (m_num < m_maxSize) { bool flag = addConnection(); if (!flag) { return; } std::unique_lock<std::mutex> lock(m_mutex); while (m_connkQueue.size() >= m_min_conn) { // è¿æ¥éåçæ°éå¤§äºæå°çè¿æ¥æ° m_cond.wait(lock); } // å¤é m_cond1.notify_all(); addConnection(); } } void ConnectionPool::recycleConnection() { while (true) { // ä¼ç 䏿®µæ¶é´ 0.5s this_thread::sleep_for(milliseconds(500)); lock_guard<mutex> lc(m_mutex); while (!m_connections.empty() && m_num > m_minSize) { MysqlConn* conn = m_connections.front(); if (conn->getAliveTime() >= m_maxIdleTime) { m_connections.pop(); // å é¤ç©ºé²è¿æ¥ void ConnectionPool::recycle() { while ( true ) { std::this_thread::sleep_for( std::chrono::milliseconds(500)); // ä¼ç 500 ms std::unique_lock<std::mutex>lock(m_mutex); while ( m_connkQueue.size() > m_min_conn ) { MysqlConn* conn = m_connkQueue.front( ); if (conn->getActiveTime() >= max_del_time) { m_connkQueue.pop(); delete conn; --m_num; } else { break; @@ -97,35 +103,22 @@ } } } ConnectionPool* ConnectionPool::getConnectPool() { // ä¸ä½¿ç¨äºæ¥éç线ç¨å®å ¨çææ±æ¨¡å¼ static ConnectionPool pool; // åªå¨ç¬¬ä¸æ¬¡è°ç¨å½æ°æ¶åå§å return &pool; } shared_ptr<MysqlConn> ConnectionPool::getConnection() { unique_lock<mutex> lc(m_mutex); while (m_connections.empty()) { if (cv_status::timeout == m_cond1.wait_for(lc, chrono::milliseconds(m_timeout))) { if (m_connections.empty()) { // cout << "out of time" << endl; return nullptr; // ç»æ // æç¤º // continue; // å©ç¨whileé åcontinue ç»§ç»é»å¡ } std::shared_ptr<MysqlConn> ConnectionPool::getMysqlConn() { std::unique_lock<std::mutex>lock(m_mutex); while ( m_connkQueue.empty()) { // 妿çå¾ ä¸æ®µæ¶é´å,éåè¿æ¯ä¸ºç©º,è¿åä¸ä¸ª null if ( std::cv_status::timeout == m_cond.wait_for(lock, std::chrono::milliseconds(m_timeout)) ) { if( m_connkQueue.empty( ) ) return nullptr; } } // è¦æå®å é¤å¨destructorï¼æ¥ä¿è¯è¿æ¥çå½è¿ shared_ptr<MysqlConn> conn(m_connections.front(), [this](MysqlConn* conn) { // å éä¿è¯éå线ç¨å®å ¨ // m_mutex.lock(); // 1 unique_lock<mutex> lc(m_mutex); // 2 // lock_guard<mutex> lc(m_mutex); // 3 conn->refreashAliveTime(); m_connections.push(conn); // m_mutex.unlock(); // 1 std::shared_ptr<MysqlConn> connPtr(std::move(m_connkQueue.front()), [this](MysqlConn* conn) { std::unique_lock <std::mutex>lock(m_mutex) ; conn->refreshActiveTime(); m_connkQueue.push(conn); }); m_connections.pop(); m_cond.notify_all(); return conn; } m_connkQueue.pop(); m_cond.notify_one(); // å¤éé»å¡çç产è 线ç¨,å¼å§ç产 return connPtr; } Server/ÍõçûÔª/code/ConnectionPool.h
@@ -1,54 +1,50 @@ #pragma once #include "MysqlConn.h" #include "./tinyxml/tinyxml.h" #include <queue> #include <mutex> #include <thread> #include <atomic> #include <condition_variable> #include <json/json.h> #include "MysqlConn.h" #pragma comment(lib, "./tinyxml/x64/Debug/tinyxml.lib") using namespace Json; // åºç¨-å便¨¡å¼ï¼ææ±æ¨¡å¼[éè¦èèå¤çº¿ç¨å®å ¨é®é¢] class ConnectionPool { private: ConnectionPool(); // ç§»å¨æ·è´æç»è¿æ¯æä¸ä» æä¸ä¸ªå¯¹è±¡ï¼æä»¥ä¾æ§æ¯å±äºå便¨¡å¼ã // delete 黿¢æ·è´æé åæ·è´èµå¼çç±»å¯¹è±¡çæ ConnectionPool(ConnectionPool&) = delete; ConnectionPool& operator=(ConnectionPool&) = delete; ~ConnectionPool(); // è§£æxmlé ç½®æä»¶ è¯»åæ°æ®åºåè¿æ¥æ± çç¸å ³ä¿¡æ¯ bool parseXmlFile(); // æ·»å è¿æ¥ bool addConnection(); // 线ç¨å½æ° void productConnection(); void recycleConnection(); // åæ¾æ°æ®åºè¿æ¥æ± 建ç«çè¿æ¥ queue<MysqlConn*> m_connections; // ä¸äºåºæ¬ä¿¡æ¯ string m_ip; // IP unsigned short m_port; // ç«¯å£ string m_user; // ç¨æ·å string m_passwd; // å¯ç string m_dbName; // æ°æ®åºåç§° int m_minSize; // åå§è¿æ¥é(æå°è¿æ¥é) int m_maxSize; // æå¤§è¿æ¥é int m_timeout; // è¶ æ¶æ¶é¿ int m_maxIdleTime; // æå¤§ç©ºé²æ¶é¿ // 线ç¨å®å ¨ç¸å ³ mutex m_mutex; condition_variable m_cond; // ä» ç¨ä¸ä¸ªæ¡ä»¶å鿥å¤é线ç¨ï¼ä½å¹¶ä¸å½±å线ç¨è¿è¡ condition_variable m_cond1; // è¿æ¥æ°é atomic_int m_num; // è¿æ¥çæ»æ°é public: // è·ååä¾å¯¹è±¡çæ¥å£ static ConnectionPool* getConnectPool(); // ç¨æ·è·åè¿æ¥çæ¥å£, 妿è·å失败ï¼ä¼è¿ånullptr shared_ptr<MysqlConn> getConnection(); static ConnectionPool* getInstance( ); std::shared_ptr<MysqlConn> getMysqlConn(); // 仿°æ®åºè¿æ¥æ± è·åè¿æ¥ ConnectionPool(const ConnectionPool& other) = delete; ConnectionPool& operator = (const ConnectionPool & other ) = delete; ~ConnectionPool(); void description(); protected: ConnectionPool( ); // æé 彿° private: bool parseJsonFile(); // è§£æé ç½® void produce(); void recycle(); void addConnection(); // å¢å è¿æ¥æ° std::string m_ip; std::string m_userName; std::string m_passwd; std::string m_db; unsigned short m_port; int m_max_conn; int m_min_conn; int m_timeout; // è¿æ¥è¶ æ¶æ¶é´ int max_del_time; // æå¤§å 餿¶é´( è¿æ¥ç©ºé²æ¶é´è¶ è¿è¿ä¸ª,å°±ç»å½åè¿æ¥å ³é ) std::queue<MysqlConn*>m_connkQueue ; // è¿æ¥éå std::mutex m_mutex; // äºæ¥é std::condition_variable m_cond; // æ¡ä»¶åé }; Server/ÍõçûÔª/code/MysqlConn.cpp
@@ -1,174 +1,115 @@ #include "MysqlConn.h" #include <regex> // åå§åè¿æ¥ MysqlConn::MysqlConn() { mysql_ = mysql_init( mysql_ ); // 设置å符é if( mysql_ ) mysql_set_character_set(mysql_ , "gbk"); } MysqlConn::MysqlConn()//åå§åæ°æ®åº { m_result = nullptr; m_mysqlRow = nullptr; // ä¼ å ¥nullptr空æéæ¶ï¼ä¼èªå¨åé ä¸ä¸ªMYSQL对象 m_conn = mysql_init(nullptr); } MysqlConn::~MysqlConn()//éæ¾æ°æ®åºè¿æ¥ { freeRes(); // éæ¾ç»æé if (m_conn != nullptr) { mysql_close(m_conn); m_conn = nullptr; } } void MysqlConn::freeRes()//ç»æééæ¾ { if (m_result) { mysql_free_result(m_result); m_result = nullptr; } } bool MysqlConn::connect(const string user, const string passwd, \ const string dbName, string ip, \ const unsigned short port)//è¿æ¥æ°æ®åº { MYSQL* res = mysql_real_connect(m_conn, ip.c_str(), user.c_str(), \ passwd.c_str(), dbName.c_str(), port, nullptr, 0); // ä¿®æ¹ç¼ç mysql_set_character_set(m_conn, "gb2312"); return res != nullptr; } bool MysqlConn::update(const string sql) const { // æ§è¡æåè¿å0ï¼ int res = mysql_real_query(m_conn, sql.c_str(), static_cast<unsigned int>(sql.size())); if (res != 0) { return false; // æç¤º // è¿æ¥æ°æ®åº bool MysqlConn::connect( std::string ip, std::string userName, std::string passwd, std::string db, int port ) { mysql_ = mysql_real_connect(mysql_, ip.c_str(), userName.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0); if (!mysql_) { return false; } return true; } bool MysqlConn::query(const string sql) { // éæ¾èµæº MysqlConn::~MysqlConn() { if (mysql_) { mysql_close(mysql_); mysql_ = nullptr; } freeRes(); int res = mysql_real_query(m_conn, sql.c_str(), static_cast<unsigned int>(sql.size())); if (res != 0) { return false; // æç¤º } // æ´æ°æ°æ® bool MysqlConn::update( std::string sql ) { if (!isSqlSafe(sql)) { return false; } m_result = mysql_store_result(m_conn); int ret = mysql_query( mysql_ , sql.c_str()); if( ret != 0 ){ return false; } return true; } bool MysqlConn::getRes() { if (m_result != nullptr) { // char** è·ååè¡è®°å½ m_mysqlRow = mysql_fetch_row(m_result); if (m_mysqlRow != nullptr) { return true; } freeRes(); // æ¥è¯¢æ°æ®åº bool MysqlConn::query(std::string sql) { freeRes( ); if (!isSqlSafe(sql)) { return false; } int ret = mysql_query(mysql_, sql.c_str()); if (ret != 0) return false; // è·åæ¥è¯¢ç»æ res_ = mysql_store_result(mysql_); if (!res_) return false; return true; } // å¾å°ç»æé bool MysqlConn::getResult() { if (res_) { row_ = mysql_fetch_row(res_); if(row_) return true; } return false; } string MysqlConn::getValue(const int fieldIndex) const { int fieldCount = mysql_num_fields(m_result); if (fieldIndex >= fieldCount || fieldIndex < 0) { return string(); // æç¤º } char* value = m_mysqlRow[fieldIndex]; // å¾å°ä¸ä¸ªä¿åååæ®µå¼é¿åº¦çæ°ç» unsigned long* len = mysql_fetch_lengths(m_result); unsigned long length = len[fieldIndex]; // 鲿¢ç»æä¸åå¨\0å¯¼è´æ°æ®ä¸¢å¤± return string(value, length); } bool MysqlConn::selectDB(const string dbName) const { int res = mysql_select_db(m_conn, dbName.c_str()); if (res != 0) { return false; // æç¤º } return true; } void MysqlConn::backupCurrentDB(const string path) { string sql = "show tables"; int r = mysql_real_query(m_conn, sql.c_str(), static_cast<unsigned long>(sql.size())); if (r != 0) { return; // æç¤º } MYSQL_RES* tableRes = mysql_store_result(m_conn); for (int i = 0; i < mysql_num_rows(tableRes); ++i) { MYSQL_ROW tableName = mysql_fetch_row(tableRes); backupCurrentTable(path, tableName[0]); } } void MysqlConn::backupCurrentTable(const string path, const string tableName) { string file = path + tableName + ".sql"; ofstream ofs(file); if (!ofs.is_open()) { return; // æç¤º } // è¡¨ç»æåå ¥ string showCreate = "show create table " + tableName + ";"; bool res = query(showCreate); if (!res) { return; // æç¤º } if (getRes()) { string writeSQL = getValue(1) + ";\n"; ofs.write(writeSQL.c_str(), writeSQL.size()); // cout << writeSQL << endl; } // è¡¨æ°æ®åå ¥ string sql = "select * from " + tableName + ";"; res = query(sql); if (!res) { return; // æç¤º } while (getRes()) { string writeSQL = "insert into `" + tableName + "` values("; for (int i = 0; !getValue(i).empty(); ++i) { if (i != 0) { writeSQL += ","; } MYSQL_FIELD* valueType = mysql_fetch_field_direct(m_result, i); if (valueType->type == MYSQL_TYPE_DECIMAL || valueType->type == MYSQL_TYPE_TINY || valueType->type == MYSQL_TYPE_SHORT || valueType->type == MYSQL_TYPE_LONG || valueType->type == MYSQL_TYPE_FLOAT || valueType->type == MYSQL_TYPE_DOUBLE || valueType->type == MYSQL_TYPE_TIMESTAMP || valueType->type == MYSQL_TYPE_LONGLONG || valueType->type == MYSQL_TYPE_INT24) { writeSQL += getValue(i); } else { writeSQL += "'" + getValue(i) + "'"; } } writeSQL += ");\n"; ofs.write(writeSQL.c_str(), writeSQL.size()); } ofs.close(); } bool MysqlConn::transaction() const { // å°äºå¡æäº¤è®¾ç½®ä¸ºæå¨æäº¤ return mysql_autocommit(m_conn, false); } bool MysqlConn::commit() const { return mysql_commit(m_conn); } bool MysqlConn::rollback() const { return mysql_rollback(m_conn); } void MysqlConn::refreashAliveTime() { m_alivetime = steady_clock::now(); } ll MysqlConn::getAliveTime() { // æ¯«ç§ <<= 纳ç§:精度éä½ milliseconds res = duration_cast<milliseconds>(steady_clock::now() - m_alivetime); return res.count(); // è·åç»æéçåæ®µ std::string MysqlConn::getField( int index ) { int cols = mysql_num_fields(res_); if ( index >= cols || index < 0 ) return std::string(""); char* value = row_[index]; unsigned long len = mysql_fetch_lengths(res_)[index]; return std::string(value, len); } // äºå¡æä½ bool MysqlConn::transaction() { return mysql_autocommit(mysql_ ,false ); } // æäº¤äºå¡ bool MysqlConn::commit() { return mysql_commit(mysql_); } // äºå¡åæ» bool MysqlConn::rollback() { return mysql_rollback(mysql_); } void MysqlConn::refreshActiveTime() { activeTime_ = std::chrono::steady_clock::now(); } long long MysqlConn::getActiveTime() { // 纳米 std::chrono::nanoseconds nased = std::chrono::steady_clock::now() - activeTime_; // è½¬æ¢ææ¯«ç±³ std::chrono::microseconds millsed = std::chrono::duration_cast<std::chrono::microseconds>( nased ); return millsed.count( ); // å¤å°æ¯«ç§ } // å®å ¨æ ¡éªå®ç°ï¼è¿éç®åä½¿ç¨æ£å表达å¼å¤ææ¯å¦å å«å±é©å符 bool MysqlConn::isSqlSafe(const std::string& sql) { std::regex dangerousPattern(".*(['\";\\-+=]).*"); return!std::regex_search(sql, dangerousPattern); } void MysqlConn::freeRes() { if (res_) { mysql_free_result(res_); res_ = nullptr; } } Server/ÍõçûÔª/code/MysqlConn.h
@@ -1,63 +1,46 @@ #pragma once #include<iostream> #include <memory> #include <string> #include <mysql.h> #include <chrono> // æ¶é #include <fstream> #pragma comment(lib, "./lib/libmysql.lib") // å è½½æ°æ®åºåºæä»¶ using namespace std; using namespace chrono; typedef long long ll; #include <string> #include <WinSock2.h> #include <mysql.h> #include <string.h> #include <chrono> class MysqlConn { private: // ç»å¯¹æ¶é steady_clock::time_point m_alivetime; // è¿æ¥ MYSQL* m_conn; // æ¥è¯¢çç»æé MYSQL_RES* m_result; // åè®°å½ç»æé MYSQL_ROW m_mysqlRow; // ç»æééæ¾ void freeRes(); // å¯¼åºæä¸å¼ 表ä¸çæ°æ® void backupCurrentTable(const string path, const string tableName); public: // åå§åæ°æ®åº // åå§åè¿æ¥ MysqlConn(); // æ°æ®åºè¿æ¥éæ¾ ~MysqlConn(); // è¿æ¥æ°æ®åº, éæä¾ç¨æ· å¯ç æ°æ®åºåç§° ip ç«¯å£ bool connect(const string user, const string passwd, \ const string dbName, string ip, \ const unsigned short port = 3306U); // æ´æ°æ°æ®åº:å¢å æ¹æä½ bool update(const string sql) const; // è¿æ¥æ°æ®åº bool connect(std::string ip, std::string userName, std::string passwd, std::string db , int port = 3306); // éæ¾èµæº ~MysqlConn( ); // æ´æ°æ°æ®åº ( insert update delete ) bool update(std::string sql); // æ¥è¯¢æ°æ®åº bool query(const string sql); // éåæ¥è¯¢ç»æé bool getRes(); // è·åç»æéä¸çåæ®µå¼ string getValue(const int fieldIndex) const; // åæ¢æ°æ®åº bool selectDB(const string dbName) const; // å»ºåº //bool createDB(const string dbName) const; // å¤ä»½æä¸ªåº void backupCurrentDB(const string path); bool query(std::string sql); // å¾å°ç»æé bool getResult(); // è·åç»æéçåæ®µ std::string getField(int index); // äºå¡æä½ bool transaction() const; bool transaction(); // æäº¤äºå¡ bool commit() const; bool commit( ); // äºå¡åæ» bool rollback() const; // å·æ°èµ·å§çç©ºé²æ¶é´ç¹ void refreashAliveTime(); // 计ç®åæ´»æ»æ¶é¿ ll getAliveTime(); bool rollback(); void refreshActiveTime( ); // å·æ°æ´»è·æ¶é´ long long getActiveTime(); // è·åå½åæ´»è·çæ¶é´é´é // å®å ¨æ ¡éªæ¥å£ bool isSqlSafe(const std::string& sql); private: void freeRes(); MYSQL* mysql_ = NULL ; MYSQL_RES* res_ = NULL; MYSQL_ROW row_ = nullptr; std::chrono::steady_clock::time_point activeTime_; };