• webserver——三、数据库


    数据库连接池类

    • 使用池的原因是因为数据库的连接和释放很消耗资源,如果每次需要数据库的时候再进行连接非常耗时。
    • 使用单例模式

    class connection_pool

    接口:

    • static connect_pool *GetInstance() :单例模式,获取数据库池对象指针
    • void init(…):数据库初始化,输入数据库的用户密码和对哪个数据库进行操作。
    • MYSQL *GetConnection() :获取数据库连接 ,无可用连接时候会阻塞。
    • bool ReleaseConnection(MYSQL*) :把之前获取到的数据库连接放回去。
    • int GetFreeConn():当前连接池有多少可用连接。

    实现

    #include "mysql/mysql.h"
    #include "../lock/locker.h"
    #include "list"
    #include "string"
    
    class connection_pool{
    public:
        //获取数据库池对象指针。
        static connection_pool *GetInstance();
        //初始化
        void init(std::string host, int port, std::string user_name, std::string password, std::string db_name, int max_conn);
        //获取一个数据库连接
        MYSQL *GetConnection();
        //释放一个连接
        bool ReleaseConnection(MYSQL* &);
        //获取当前可用的连接数目
        int GetFreeConn(){
            return m_free_conn;
        }
    private:
        connection_pool();
        ~connection_pool();
    private:
        //可用数据库连接列表
        std::list<MYSQL*> m_list;
        //可用连接数目
        int m_free_conn;
        //信号量,用于连接的获取和释放
        sem m_sem;
        //互斥锁,用于获取连接和释放连接时候的
        locker m_locker;
    };
    /*实现*/
    connection_pool::connection_pool():m_free_conn(0){}
    connection_pool::~connection_pool(){
        MutexLockGuard lock(m_locker);
        for(auto iter = m_list.begin(); iter != m_list.end(); ++iter){
            //关闭连接
            if(*iter != nullptr)
                mysql_close(*iter);
        }
    }
    
    //c++11之后的线程安全懒汉模式
    connection_pool *connection_pool::GetInstance(){
        static connection_pool m_instance;
        return &m_instance;
    }
    
    //多次init会导致不可预测的后果
    void connection_pool::init(std::string host, int port, std::string user_name, std::string password, std::string db_name, int max_conn){
        MutexLockGuard lock(m_locker);
        
        if(max_conn <= 0)
            max_conn = 3;
        
        for(int i = 0; i != max_conn; ++i){
            MYSQL *mysql_handler = nullptr;
            mysql_handler = mysql_init(mysql_handler);
            if(!mysql_handler){
                printf("mysql connect error\n");
                continue;
            }
            mysql_handler = mysql_real_connect(mysql_handler, host.c_str(), user_name.c_str(), password.c_str(), db_name.c_str(), port, nullptr, 0);
            if(!mysql_handler){
                printf("mysql connect error\n");
                continue;
            }
            m_list.push_back(mysql_handler);
            ++m_free_conn;
                  
        }
        //再次给信号量赋值
        m_sem = sem(m_free_conn);
        
    }
    
    //获取连接
    MYSQL *connection_pool::GetConnection(){
        MYSQL *res = nullptr;
        if(m_list.empty())
            return res;
        m_sem.wait();
        {
            MutexLockGuard lock(m_locker);
            res = m_list.front();
            m_list.pop_front();
            --m_free_conn;
        }
        return res;
    }
    
    //释放连接
    bool connection_pool::ReleaseConnection(MYSQL *&conn){
        if(conn == nullptr) return false;
        MutexLockGuard lock(m_locker);
        m_list.push_back(conn);
        ++m_free_conn;
        m_sem.post();
        conn = nullptr;
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    要点:

    • 单例模式采用的是C++0x之后才支持的线程安全的static初始化的一个操作,也就是
    connection_pool *connection_pool::GetInstance(){
        static connection_pool m_instance;
        return &m_instance;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 在析构函数的时候关闭mysql连接,由于对数据库连接池采用的是单例模式,所以之后进程结束才会进行析构,也就不用考虑有些mysql连接还没释放的情况了。
    for(auto iter = m_list.begin(); iter != m_list.end(); ++iter){
            //关闭连接
            if(*iter != nullptr)
                mysql_close(*iter);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 释放连接的时候对MYSQL*参数使用的是引用传参,并且在放回m_list之后回把参数置nullptr,这样就防止了一边把数据库资源还给连接池,一边继续使用的情况发生。
    //释放连接
    bool connection_pool::ReleaseConnection(MYSQL *&conn){
        if(conn == nullptr) return false;
        MutexLockGuard lock(m_locker);
        m_list.push_back(conn);
        ++m_free_conn;
        m_sem.post();
        conn = nullptr;
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    总结:

    • 使用之前要先init()初始化,并且注意init函数不能多次调用,多次调用会引发不可预测的后果。
    • 使用GetConnection()获取一个MYSQL*数据库连接,获取连接的时候不会阻塞,当发现连接池中没有可用连接后,直接返回nullptr。
    • ReleaseConnection()释放一个MYSQL*连接。

    添加:使用RAII管理数据库连接池,用来自动释放连接。

    • 使用数据库连接池初始化ConnectRAII,初始化之后的ConnectRAII对象会持有一个数据库连接对象,通过getConn获取这个对象,当离开作用域后,这个对象会自己释放。
    class ConnectRAII{
    public:
        ConnectRAII(connection_pool* connectpool){
            m_mysql = connectpool->GetConnection();
            m_conn_pool = connectpool;
        }
        ~ConnectRAII(){
            m_conn_pool->ReleaseConnection(m_mysql);
        }
        MYSQL* getConn(){
            return m_mysql;
        }
    private:
        MYSQL* m_mysql;
        connection_pool* m_conn_pool;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    使用Node解析EML文件
    7.MySQL DQL(数据查询语言) 语句
    innobackupex备份恢复,全备,增备,恢复单库单表
    .net framework、.net standard、 .net core .net 5/6 区别
    C#脚本CSharpScript
    idea灰屏问题
    C++从0吃透string类
    Unity Shader—04 Unity中的基础光照
    pytorch实现图像的腐蚀和膨胀
    SAP PO运维(二):XML消息归档和删除配置
  • 原文地址:https://blog.csdn.net/qq_42370809/article/details/126142786