紫影基地

 找回密码
 立即注册
查看: 157|回复: 0

基于C++实现Mysql数据库连接池实例

[复制链接]
阅读字号:

35

主题

39

帖子

6649

积分

论坛元老

Rank: 8Rank: 8

积分
6649
发表于 2024-6-4 04:28:06 | 显示全部楼层 |阅读模式

  1. 数据库连接池负责分配、管理、和释放数据库连接,允许使用应用程序重复使用一个现有的数据库连接。数据库连接是关键有限且昂贵的资源,一个数据库连接对象均对应一个物理数据库的连接,每次操作都打开一个物理连接,使用完都关闭连接.

  2. 基于C++实现Mysql数据库连接池实例

  3. 项目技术点
  4. C语言进行MYSQL数据库编程
  5. 无锁单例
  6. 基于STL队列加C++11新特性保证线程安全实现的生产者消费者模型
  7. C++11多线程编程 (线程间同步与互斥)
  8. 基于CAS的原子整形
  9. lambda表达式
  10. shared_ptr智能指针管理Connection*指针对象
  11. 基于C++11标准库实现, 具备跨平台的特性,省去了对于pthread库的C++的封装.更加针对于项目的核心逻辑上的思考和实现. (主干到细节)
  12. Makefile自动化编译
  13. 项目意义
  14. 高并发场景下, 频繁创建, 销毁连接带来的性能损耗

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

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

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

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

  19. 思考: connections 数目设计?

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

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

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

  23. 项目实现
  24. Connection设计
  25. 数据成员

  26. MYSQL* _conn; //连接句柄  
  27. clock_t _startTime;   //连接起始空闲时间
  28. 操作接口

  29. Connection();//构造 init Connection
  30. ~Connection();   //析构 destroy connection
  31. bool connect(ip, port, username, password, dbname); //连接操作, 返回连接结果
  32. bool update(sql);//表更新操作, 返回更新结果
  33. MYSQL_RES* query(sql);   //查询操作, 返回查询结果
  34. void refreshStartTime(); //刷新连接起始空闲时间
  35. clock_t getAliveTime();  //获取连接空闲时间
  36. ConnectionPool设计
  37. 数据成员

  38. //连接登录信息
  39. string _ip;
  40. unsigned short _port;
  41. string _username;
  42. string _password;
  43. string _dbname;
  44. //连接数量等配置信息
  45. int _initSize;
  46. int _maxSize;
  47. int _maxIdleTime;
  48. int _connectionTimeout;
  49. //连接存储信息,以及保证线程安全
  50. queue<Connection*> _connectionQue;
  51. mutex _queueLock;
  52. condition_variable _cond;
  53. atomic_int _connectionCnt;
  54. 操作接口

  55. ConnectionPool();  //构造 init pool, 加载配置, 初始连接, 启动线程
  56. static ConnectionPool* getConnectionPool();//获取单例
  57. shared_ptr<Connection> getConnection();//获取连接
  58. int _loadConfigFile(string& filename); //加载解析配置信息
  59. void produceConnectionTask();  //生产连接任务
  60. void scannerConnetionTask();   //扫描监视销毁空闲线程任务
  61. 项目复杂接口细节刨析
  62. getConnection()

  63. /*
  64. 从连接池中获取一条连接. 相当于是消费者
  65. 消费前提, _connectionQue中有货, 所以无货期间需要进行阻塞休眠等待.
  66. 等待也不能一直等待. 存在连接超时时间,
  67. waittime >= _connectionTimeout then output << error.
  68. */
  69. shared_ptr<Connection> getConnection() {
  70. unique_lock<mutex> auto_lock(_queueLock);//定义智能锁
  71. while (_connectionQue.empty()) {
  72. if (cv_status::timeout == _cond.wait_for(auto_lock,  chrono::milliseconds(_connectionTimeout))) { //达到连接超时时间
  73. if (_connectionQue.empty()) {
  74. //LOG DEBUG INFO
  75. cerr << "获取连接超时" << endl;
  76. return nullptr;
  77. }
  78. }
  79. }
  80. //定义shared_ptr<Connection> 自定义del函数, 而非直接调用~T()
  81. shared_ptr<Connection> sp(_connectionQue.front(), [&](Connection* pconn){
  82. unique_lock<mutex> auto_lock(_queueLock);
  83. pconn->refreshStartTime();  //刷新连接起始空闲时间
  84. _connectionQue.push(pconn);
  85. });
  86. _connectionQue.pop();
  87. _cond.notify_all(); //弹出任务, queue maybe empty notify produce
  88. return sp;
  89. }
  90. produceConnectionTask()

  91. /*
  92. 生产者线程任务. 在_connectionQue中无connetion
  93. && _connectionCnt < _maxSize 时候 及时创建连接填充_connectionQue。   
  94. */
  95. void produceConnectionTask() {
  96. for (;;) {
  97. unique_lock<mutex> auto_lock(_queueLock);
  98. while (!_connectionQue.empty()) {
  99. _cond.wait(auto_lock);
  100. }
  101. if (_connectionCnt < _maxSize) {
  102. Connection* pconn = new Connection();
  103. pconn->connet(_ip, _port, _username, _password, _dbname);
  104. pconn->refreshStartTime();
  105. _connectionQue.push(pconn);
  106. _connectionCnt++;
  107. }
  108. _cond.notify_all(); //通知消费
  109. }
  110. }

  111. scannerConnetionTask()

  112. /*
  113.         不停的扫描所有的connection, 从头到尾的扫描,
  114. 监控销毁哪些长期空闲的connection, 避免对于空闲资源的无端占用浪费.  
  115. 每一次休眠一个 _maxIdleTime 就出来 检查, 定期轮询检查空闲丽连接进行销毁
  116. */
  117. void scannerConnectionTask() {
  118. for (;;) {
  119. //休眠maxIdleTime
  120.         this_thread::sleep_for(chrono::seconds(_maxIdleTime));   
  121. unique_lock<mutex> auto_lock(_queueLock);
  122. while (_connectionCnt > _initSize)
  123.                 {
  124.                         Connection *p = _connectionQue.front();
  125.                         if (p->getAliveeTime()/SECONDS_PER_SEC >= _maxIdleTime)
  126.                         {
  127.                                 _connectionQue.pop();
  128.                                 _connectionCnt--;
  129.                                 delete p; // 调用~Connection()释放连接
  130.                         }
  131.                         else
  132.                         {
  133.                                 break; // 队头的连接没有超过_maxIdleTime,其它连接肯定没有
  134.                         }
  135.                 }   
  136. }
  137. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|紫影基地

GMT+8, 2025-1-12 08:49 , Processed in 0.083815 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表