240717班级,工业化控制系统,煤矿相关行业,昆仑系统
1
wangky
2024-10-31 9583a7be21958cafdf30f03526dbf68838aa883f
1
4个文件已添加
422 ■■■■■ 已修改文件
Server/王琨元/code/ConnectionPool.cpp 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/ConnectionPool.h 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/MysqlConn.cpp 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/MysqlConn.h 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/ÍõçûÔª/code/ConnectionPool.cpp
New file
@@ -0,0 +1,131 @@
#include "ConnectionPool.h"
ConnectionPool::ConnectionPool()
{
    if (!parseXmlFile())
        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); // æ£€æµ‹å¹¶é”€æ¯è¿žæŽ¥
                                                               // çº¿ç¨‹åˆ†ç¦»ï¼Œé˜²æ­¢é˜»å¡žä¸»çº¿ç¨‹
    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;
        return true;
    }
    else {
        delete conn;
        return false; // æç¤º
    }
}
void ConnectionPool::productConnection()
{
    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;
            }
        }
        // å”¤é†’
        m_cond1.notify_all();
    }
}
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();
                delete conn;
                --m_num;
            }
            else {
                break;
            }
        }
    }
}
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 ç»§ç»­é˜»å¡ž
            }
        }
    }
    // è¦æŒ‡å®šåˆ é™¤å™¨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
        });
    m_connections.pop();
    m_cond.notify_all();
    return conn;
}
Server/ÍõçûÔª/code/ConnectionPool.h
New file
@@ -0,0 +1,54 @@
#pragma once
#include "MysqlConn.h"
#include "./tinyxml/tinyxml.h"
#include <queue>
#include <mutex>
#include <thread>
#include <atomic>
#include <condition_variable>
#pragma comment(lib, "./tinyxml/x64/Debug/tinyxml.lib")
// åº”用-单例模式:懒汉模式[需要考虑多线程安全问题]
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();
};
Server/ÍõçûÔª/code/MysqlConn.cpp
New file
@@ -0,0 +1,174 @@
#include "MysqlConn.h"
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; // æç¤º
    }
    return true;
}
bool MysqlConn::query(const string sql)
{
    freeRes();
    int res = mysql_real_query(m_conn, sql.c_str(), static_cast<unsigned int>(sql.size()));
    if (res != 0) {
        return false; // æç¤º
    }
    m_result = mysql_store_result(m_conn);
    return true;
}
bool MysqlConn::getRes()
{
    if (m_result != nullptr) {
        // char** èŽ·å–å•è¡Œè®°å½•
        m_mysqlRow = mysql_fetch_row(m_result);
        if (m_mysqlRow != nullptr) {
            return true;
        }
        freeRes();
    }
    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();
}
Server/ÍõçûÔª/code/MysqlConn.h
New file
@@ -0,0 +1,63 @@
#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;
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 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 transaction() const;
    // æäº¤äº‹åŠ¡
    bool commit() const;
    // äº‹åŠ¡å›žæ»š
    bool rollback() const;
    // åˆ·æ–°èµ·å§‹çš„空闲时间点
    void refreashAliveTime();
    // è®¡ç®—存活总时长
    ll getAliveTime();
};