240717班级,工业化控制系统,煤矿相关行业,昆仑系统
1
wangky
2024-11-04 4b032971d376b063480e53842045561f7c9b399b
1
4个文件已修改
631 ■■■■■ 已修改文件
Server/王琨元/code/ConnectionPool.cpp 203 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/ConnectionPool.h 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/MysqlConn.cpp 261 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Server/王琨元/code/MysqlConn.h 85 ●●●●● 补丁 | 查看 | 原始文档 | 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_;
};