当前位置:   article > 正文

Mysql数据库连接池的简单实现(基于C++11), 基础学完, 包教包会._c++ mysql连接池

c++ mysql连接池

项目技术点

  1. C语言进行MYSQL数据库编程

  2. 无锁单例

  3. 基于STL队列加C++11新特性保证线程安全实现的生产者消费者模型

  4. C++11多线程编程 (线程间同步与互斥)

  5. 基于CAS的原子整形

  6. lambda表达式

  7. shared_ptr智能指针管理Connection*指针对象

  8. 基于C++11标准库实现, 具备跨平台的特性,省去了对于pthread库的C++的封装.更加针对于项目的核心逻辑上的思考和实现. (主干到细节)

  9. Makefile自动化编译

项目意义

高并发场景下, 频繁创建, 销毁连接带来的性能损耗

三次握手,连接认证(身份权限认证),MySQL资源释放, 四次挥手

每一次client 访问 Mysql server都需要进行上述操作. 上述这些操作是固定的流程. 真正的sql语句执行操作才是我们无法逃脱的, 所以上述这些我们完全可以提前创建出来,然后进行不断的复用connections. 实现mysql server访问的性能提升.

思考: 提前创建好的 connetions 数目是否是越多越好?

当然是不可能,因为每一个connection都是需要占据一定的系统资源的, 创建过多的connection 会导致服务器资源紧张. 起码per connection per socketfd (套接字资源)

思考: connections 数目设计?

上下限限制数目. initSize控制下限. maxSize控制连接上限 (一般是系统的最大mysql connetions num)

多余connection最长闲置时间限制: maxIdleTime (及时释放闲置连接)

资源紧张, 并发访问量高. 没有连接可用 :connectionTimeout (return error, 获取连接超时时间)

项目实现

Connection设计

数据成员

  1. MYSQL* _conn;         //连接句柄                                  
  2. clock_t _startTime;   //连接起始空闲时间

操作接口

  1. Connection();            //构造 init Connection
  2. ~Connection();           //析构 destroy connection
  3. bool connect(ip, port, username, password, dbname);     //连接操作, 返回连接结果
  4. bool update(sql);        //表更新操作, 返回更新结果
  5. MYSQL_RES* query(sql);   //查询操作, 返回查询结果
  6. void refreshStartTime(); //刷新连接起始空闲时间
  7. clock_t getAliveTime();  //获取连接空闲时间

ConnectionPool设计

数据成员

  1. //连接登录信息
  2. string _ip;
  3. unsigned short _port;
  4. string _username;
  5. string _password;
  6. string _dbname;
  7. //连接数量等配置信息
  8. int _initSize;
  9. int _maxSize;
  10. int _maxIdleTime;
  11. int _connectionTimeout;
  12. //连接存储信息,以及保证线程安全
  13. queue<Connection*> _connectionQue;
  14. mutex _queueLock;
  15. condition_variable _cond;
  16. atomic_int _connectionCnt;

操作接口

  1. ConnectionPool();                          //构造 init pool, 加载配置, 初始连接, 启动线程
  2. static ConnectionPool* getConnectionPool();//获取单例
  3. shared_ptr<Connection> getConnection();    //获取连接
  4. int _loadConfigFile(string& filename);     //加载解析配置信息
  5. void produceConnectionTask();              //生产连接任务
  6. void scannerConnetionTask();               //扫描监视销毁空闲线程任务

项目复杂接口细节刨析

getConnection()

  1. /*
  2. 从连接池中获取一条连接. 相当于是消费者
  3. 消费前提, _connectionQue中有货, 所以无货期间需要进行阻塞休眠等待.
  4. 等待也不能一直等待. 存在连接超时时间,
  5. waittime >= _connectionTimeout then output << error.
  6. */
  7. shared_ptr<Connection> getConnection() {
  8.    unique_lock<mutex> auto_lock(_queueLock);//定义智能锁
  9.    while (_connectionQue.empty()) {
  10.        if (cv_status::timeout == _cond.wait_for(auto_lock,                     chrono::milliseconds(_connectionTimeout))) { //达到连接超时时间
  11.            if (_connectionQue.empty()) {
  12.                //LOG DEBUG INFO
  13.                cerr << "获取连接超时" << endl;
  14.                return nullptr;
  15.           }
  16.       }
  17.   }
  18.   //定义shared_ptr<Connection> 自定义del函数, 而非直接调用~T()
  19.    shared_ptr<Connection> sp(_connectionQue.front(), [&](Connection* pconn){
  20.        unique_lock<mutex> auto_lock(_queueLock);
  21.        pconn->refreshStartTime();      //刷新连接起始空闲时间
  22.        _connectionQue.push(pconn);
  23.   });
  24.    _connectionQue.pop();
  25.    _cond.notify_all(); //弹出任务, queue maybe empty notify produce
  26.    return sp;
  27. }

produceConnectionTask()

  1. /*
  2. 生产者线程任务. 在_connectionQue中无connetion
  3. && _connectionCnt < _maxSize 时候 及时创建连接填充_connectionQue。                  
  4. */
  5. void produceConnectionTask() {
  6.    for (;;) {
  7.        unique_lock<mutex> auto_lock(_queueLock);
  8.        while (!_connectionQue.empty()) {
  9.            _cond.wait(auto_lock);
  10.       }
  11.        if (_connectionCnt < _maxSize) {
  12.            Connection* pconn = new Connection();
  13.            pconn->connet(_ip, _port, _username, _password, _dbname);
  14.            pconn->refreshStartTime();
  15.            _connectionQue.push(pconn);
  16.            _connectionCnt++;
  17.       }
  18.        _cond.notify_all(); //通知消费
  19.   }
  20. }

scannerConnetionTask()

  1. /*
  2. 不停的扫描所有的connection, 从头到尾的扫描,
  3. 监控销毁哪些长期空闲的connection, 避免对于空闲资源的无端占用浪费.
  4. 每一次休眠一个 _maxIdleTime 就出来 检查, 定期轮询检查空闲丽连接进行销毁
  5. */
  6. void scannerConnectionTask() {
  7. for (;;) {
  8. //休眠maxIdleTime
  9. this_thread::sleep_for(chrono::seconds(_maxIdleTime));
  10. unique_lock<mutex> auto_lock(_queueLock);
  11. while (_connectionCnt > _initSize)
  12. {
  13. Connection *p = _connectionQue.front();
  14. if (p->getAliveeTime()/SECONDS_PER_SEC >= _maxIdleTime)
  15. {
  16. _connectionQue.pop();
  17. _connectionCnt--;
  18. delete p; // 调用~Connection()释放连接
  19. }
  20. else
  21. {
  22. break; // 队头的连接没有超过_maxIdleTime,其它连接肯定没有
  23. }
  24. }
  25. }
  26. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/329686
推荐阅读
相关标签
  

闽ICP备14008679号