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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Mysql数据库连接池的简单实现(基于C++11), 基础学完, 包教包会.

项目技术点

C语言进行MYSQL数据库编程


无锁单例


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


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


基于CAS的原子整形


lambda表达式


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


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


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设计

数据成员

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

操作接口

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

ConnectionPool设计

数据成员

//连接登录信息
string _ip;
unsigned short _port;
string _username;
string _password;
string _dbname;
//连接数量等配置信息
int _initSize;
int _maxSize;
int _maxIdleTime;
int _connectionTimeout;
//连接存储信息,以及保证线程安全
queue<Connection*> _connectionQue;
mutex _queueLock;
condition_variable _cond;
atomic_int _connectionCnt;

操作接口

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

项目复杂接口细节刨析

getConnection()

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

produceConnectionTask()

/*
    生产者线程任务. 在_connectionQue中无connetion 
    && _connectionCnt < _maxSize 时候 及时创建连接填充_connectionQue。                   
*/
void produceConnectionTask() {
    for (;;) {
        unique_lock<mutex> auto_lock(_queueLock);
        while (!_connectionQue.empty()) {
            _cond.wait(auto_lock);
        }
        if (_connectionCnt < _maxSize) {
            Connection* pconn = new Connection();
            pconn->connet(_ip, _port, _username, _password, _dbname);
            pconn->refreshStartTime();
            _connectionQue.push(pconn);
            _connectionCnt++;
        }
        _cond.notify_all(); //通知消费
    }
}

scannerConnetionTask()

/*
  不停的扫描所有的connection, 从头到尾的扫描, 
    监控销毁哪些长期空闲的connection, 避免对于空闲资源的无端占用浪费.  
    每一次休眠一个 _maxIdleTime 就出来 检查, 定期轮询检查空闲丽连接进行销毁
*/
void scannerConnectionTask() {
    for (;;) {
        //休眠maxIdleTime
      this_thread::sleep_for(chrono::seconds(_maxIdleTime));   
        unique_lock<mutex> auto_lock(_queueLock);
        while (_connectionCnt > _initSize)
    {
      Connection *p = _connectionQue.front();
      if (p->getAliveeTime()/SECONDS_PER_SEC >= _maxIdleTime)
      {
        _connectionQue.pop();
        _connectionCnt--;
        delete p; // 调用~Connection()释放连接
      }
      else
      {
        break; // 队头的连接没有超过_maxIdleTime,其它连接肯定没有
      }
    }       
    }
}
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
SQL 监控 druid
MySQL连接池DataSource怎样使用?
**摘要:** 本文深入讨论了数据库连接池的重要性,特别是DruidDataSource,它是阿里巴巴的高性能Java数据库连接池。DruidDataSource不仅提供连接管理,还包括SQL监控和性能优化功能。文中通过代码示例展示了如何配置和使用DruidDataSource,包括在Java应用和Spring Boot中的集成,并提到了SQL执行监控和连接池参数的合理设置,强调了定期监控和使用内置监控工具以优化应用性能。
MySQL连接池DataSource怎样使用?
|
3月前
|
SQL 监控 druid
MySQL连接池DataSource是什么?
**摘要:** 本文探讨了数据库连接池在高并发Web应用中的重要性,聚焦于DruidDataSource,一个高效的Java数据库连接池组件。DruidDataSource提供连接池管理、SQL监控及性能优化功能。文中通过代码示例展示了如何配置和使用DruidDataSource,包括在Java应用中的直接配置和在Spring Boot中的集成。此外,还提到了使用技巧,如合理设置连接池参数、定期监控调整以及利用Druid的内置监控工具优化性能。
|
4月前
|
关系型数据库 MySQL 数据库
使用ZIP包安装MySQL及配置教程
使用ZIP包安装MySQL及配置教程
214 4
|
4月前
|
SQL 关系型数据库 MySQL
C++orm使用插曲——MySQL保留字
C++orm使用插曲——MySQL保留字
37 7
|
4月前
|
监控 Java 数据库连接
Java开发者必读:连接池技术如何提升数据库连接效率
【6月更文挑战第24天】Java开发中,面对高并发的数据库访问,连接池技术成为性能优化的关键。它预先创建连接池,减少频繁的连接创建/关闭,提升响应速度,节省资源,并增强系统稳定性。例如,HikariCP连接池通过配置实现DB连接管理,简化代码并提升应用性能。
35 1
|
4月前
|
Java 数据库连接 数据库
深入探索:Java连接池在数据库性能优化中的角色
【6月更文挑战第24天】Java应用中,数据库连接池如HikariCP提升性能,减少资源消耗。连接池预创建并管理连接,避免频繁创建/关闭。工作流程:申请连接→池中取或新建→使用后归还给池。示例展示了如何配置及使用HikariCP连接池,强调了其在高并发环境中的重要性。选择合适连接池并优化配置对系统性能至关重要。
44 1
|
3月前
|
SQL 监控 druid
MySQL连接池DataSource怎么使用?
**摘要:** 本文探讨了数据库连接池在高并发Web应用中的重要性,特别聚焦于阿里巴巴的DruidDataSource。DruidDataSource是一个高效的Java数据库连接池,包含监控、SQL防护和日志功能。文中通过示例展示了如何配置和使用DruidDataSource,包括在Java应用中的直接配置和在Spring Boot中的集成,并提到了启用SQL监控。此外,还分享了设置连接池参数的技巧,如合理设定初始、最大和最小连接数,并强调了定期监控和使用内置监控工具优化性能的重要性。
|
3月前
|
druid Java 数据库连接
Java面试题:解释数据库连接池的概念及其作用,讨论常见的连接池实现。
Java面试题:解释数据库连接池的概念及其作用,讨论常见的连接池实现。
59 0
|
4月前
|
关系型数据库 MySQL 分布式数据库
PolarDB操作报错合集之无法创建mysql的连接池什么导致的
在使用阿里云的PolarDB(包括PolarDB-X)时,用户可能会遇到各种操作报错。下面汇总了一些常见的报错情况及其可能的原因和解决办法:1.安装PolarDB-X报错、2.PolarDB安装后无法连接、3.PolarDB-X 使用rpm安装启动卡顿、4.PolarDB执行UPDATE/INSERT报错、5.DDL操作提示“Lock conflict”、6.数据集成时联通PolarDB报错、7.编译DN报错(RockyLinux)、8.CheckStorage报错(源数据库实例被删除)、9.嵌套事务错误(TDDL-4604)。
|
4月前
|
SQL Java 数据库连接
打破瓶颈:利用Java连接池技术提升数据库访问效率
【6月更文挑战第24天】Java连接池优化数据库访问性能,减少资源消耗。原理是预创建数据库连接池,复用连接而非频繁建立断开。优势包括性能提升、资源节约和增强稳定性。示例使用HikariCP配置连接池,动态获取和释放连接。通过连接池技术,应用能更高效地处理数据库操作。
32 0